bash + использование printf для печати в специальном формате

12

Я только что написал следующий скрипт bash, чтобы проверить доступ ping к списку машин Linux:

for M in $list
 do
   ping -q -c 1  "$M" >/dev/null 
          if [[ $? -eq 0 ]]
   then
    echo "($C) $MACHINE CONNECTION OK"
   else
    echo "($C) $MACHINE CONNECTION FAIL"
   fi

   let C=$C+1
done

Это печатает:

 (1) linux643 CONNECTION OK
 (2) linux72 CONNECTION OK
 (3) linux862 CONNECTION OK
 (4) linux12 CONNECTION OK
 (5) linux88 CONNECTION OK
 (6) Unix_machinetru64 CONNECTION OK

Как я могу использовать printf(или любую другую команду) в моем скрипте bash, чтобы напечатать следующий формат?

 (1) linux643 ............ CONNECTION OK
 (2) linux72 ............. CONNECTION OK
 (3) linux862 ............ CONNECTION OK
 (4) linux12 ............. CONNECTION OK
 (5) linux88 ............. CONNECTION FAIL
 (6) Unix_machinetru64 ... CONNECTION OK
Яэль
источник
Вы можете сделать расчет, $TOTAL (length) - $MASHINE (length)чтобы получить количество точек. Затем используйте printf '.%.s' {1..$DOTS}в каждой итерации цикла. Как-то так, думаю, сработает.
coffeMug
Можете
У вас уже есть ответ. ;-)
coffeMug
Смотрите мой ответ на StackOverflow
Приостановлено до дальнейшего уведомления.

Ответы:

19

Использование раскрытия параметров для замены пробелов, полученных в результате %-sточек:

#!/bin/bash
list=(localhost google.com nowhere)
C=1
for M in "${list[@]}"
do
    machine_indented=$(printf '%-20s' "$M")
    machine_indented=${machine_indented// /.}

    if ping -q -c 1  "$M" &>/dev/null ;  then
        printf "(%2d) %s CONNECTION OK\n" "$C" "$machine_indented"
    else
        printf "(%2d) %s CONNECTION FAIL\n" "$C" "$machine_indented"
    fi
    ((C=C+1))
done
choroba
источник
ВАУ, дайте мне проверить, и я скоро
обновлюсь
1
Хех, умный! Пара педантичных моментов: i) %2dдобавление лишних пробелов в скобках (хотя это может быть полезно, когда $ list> = 10); II), чтобы получить точный вывод ОП , вы можете добавить, machine_indented=${machine_indented/../ .}чтобы добавить дополнительный пробел перед первым .. Как я уже сказал, педантичный.
Terdon
привет, Чороба, не могли бы вы рассмотреть замечания Тердона в своем ответе?
Яэль
@yael: Теперь вам будет легко настроить решение :-)
choroba
Кстати - зачем добавлять & перед> / dev / null?
Яэль
8

for m in $listэто zshсинтаксис. В bashэтом было бы for i in "${list[@]}".

bashне имеет операторов заполнения. Вы можете выполнять заполнение, printfно только с пробелами, а не с произвольными символами. zshимеет операторы заполнения.

#! /bin/zsh -
list=(
  linux643
  linux72
  linux862
  linux12
  linux88
  Unix_machinetru64
)
c=0
for machine in $list; do
  if ping -q -c 1 $machine >& /dev/null; then
    state=OK
  else
    state=FAIL
  fi
  printf '%4s %s\n' "($((++c)))" "${(r:25::.:):-$machine } CONNECTION $state"
done

Обивка оператор ${(r:25:)parameter}с правой -pad с длиной 25 с пробелами или ${(r:25::string:)parameter}к правой -pad с любой строкой вместо пространства.

Мы также используем printf '%4s'для левой -pad (x)пробелов. Мы могли бы использовать ${(l:4:):-"($((++c)))"}вместо этого. Однако заметное отличие состоит в том, что если длина строки превышает 4 символа, она ${(l)}будет обрезана, а при ее переполнении printf.

Стефан Шазелас
источник
6

Спецификатор %sформата может иметь точность ( %.20sнапример), и точно так же, как если вы хотите вывести значение с плавающей точкой с определенной точностью ( %.4fнапример, с), вывод будет не более того количества символов из данного строкового аргумента.

Поэтому создайте строку, которая содержит имя компьютера и количество точек, достаточное для исчерпания точек:

cnt=0
for hname in vboxhost ntp.stupi.se example.com nonexistant; do
   if ping -q -c 1  "$hname" >/dev/null 2>&1; then
       status="OK"
   else
       status="FAIL"
   fi

   printf "(%d) %.20s CONNECTION %s\n" \
       "$(( ++cnt ))" "$hname ...................." "$status"

done

Вывод:

(1) vboxhost ........... CONNECTION OK
(2) ntp.stupi.se ....... CONNECTION OK
(3) example.com ........ CONNECTION OK
(4) nonexistant ........ CONNECTION FAIL
Кусалананда
источник
2

С вещами, украденными из ответа @ choroba:

#!/bin/bash 
list=(linux643 linux72 google.com linux862 linux12 linux88 unix_machinetru64) 
C=1 
readonly TOTAL=50 
for M in "${list[@]}" 
do 
    DOTS=$(( TOTAL - ${#M} ))
    ping -q -c 1  "$M" &>/dev/null 

    if (($?)) ;  then 
        printf "(%d) %s" "$C" "$M" ; printf "%0.s." $(seq 1 $DOTS) ; printf " CONNECTION FAILED\n" 
    else 
        printf "(%d) %s" "$C" "$M" ; printf "%0.s." $(seq 1 $DOTS) ; printf " CONNECTION OK\n"  
    fi 
    ((C=C+1)) 
done 
coffeMug
источник
2

Я бы сделал это с fpingи awk. К сожалению, awk«S printfне может подушечка с точками, только с пробелами или нулями , так что я должен написать функцию:

list=(kali surya indra ganesh durga hanuman nonexistent)

fping "${list[@]}" 2>&1 | 
  sort -k3 |
  awk -F'[: ]' 'BEGIN { fmt="(%02d) %s CONNECTION %s\n"};

       function dotpad(s,maxlen,     l,c,pads) {
         l = maxlen - length(s);
         pads = "";
         for (c=0;c<l;c++) {pads=pads"."};
         return s " " pads
       };

       /alive$/       { printf fmt, ++i, dotpad($1,19), "OK" };
       /unreachable$/ { printf fmt, ++i, dotpad($1,19), "FAIL" }
       /not known$/   { printf fmt, ++i, dotpad($1,19), "IMPOSSIBLE" } '
(01) durga .............. CONNECTION OK
(02) ganesh ............. CONNECTION OK
(03) indra .............. CONNECTION OK
(04) kali ............... CONNECTION OK
(05) nonexistent ........ CONNECTION IMPOSSIBLE
(06) hanuman ............ CONNECTION FAIL
(07) surya .............. CONNECTION FAIL

Я использую двузначные числа с нулями в круглых скобках, чтобы формат не облажался, если в нем 10-99 хостов $list(100+ все равно облажаются). Альтернативы можно было бы отложить до тех пор , печать на END {}блоке, и для / регулярных выражений матчей / просто вставить имя хоста в одном из трех массивов, например ok, fail, unknown. или только один ассоциативный массив (например hosts[hostname]="OK"). Затем вы можете посчитать количество строк и использовать его, чтобы решить, насколько широким должно быть поле счетчика строк.

Я также решил, что выходные данные различают неизвестные hosts ( CONNECTION IMPOSSIBLE) и недоступные хосты ( CONNECTION FAIL).

Опция sort -k3необязательна, она просто группирует выходные данные по fpingрезультату («имя хоста живо», «имя хоста недоступно» или «имя хоста: имя или служба неизвестна»). Без этого sortнеизвестные хосты всегда будут появляться первыми в выходных данных. Просто sortбез -k3сортировки по имени хоста.

саз
источник