bash + przy użyciu printf w celu drukowania w specjalnym formacie


12

Właśnie napisałem następujący skrypt bash, aby sprawdzić dostęp do pingów na liście komputerów z systemem 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

To drukuje:

 (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

Jak mogę użyć printf(lub dowolnego innego polecenia) w skrypcie bash, aby wydrukować następujący format?

 (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

Możesz wykonać obliczenia, $TOTAL (length) - $MASHINE (length)aby uzyskać liczbę kropek. Następnie użyj printf '.%.s' {1..$DOTS}w każdej iteracji pętli. Myślę, że coś takiego zadziała.
coffeMug

czy możesz opisać swoje rozwiązanie jako odpowiedź
yael

Masz już odpowiedź. ;-)
coffeMug

Odpowiedzi:


19

Używanie interpretacji parametrów do zamiany spacji wynikającej z %-skropek:

#!/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

WOW, pozwól mi sprawdzić, a wkrótce zaktualizuję ..........................
yael

1
Hej, sprytny! Kilka pedantycznych punktów: i) %2ddodaje niepotrzebne miejsce w nawiasach (chociaż może być przydatne, gdy $ list> = 10); ii) aby uzyskać dokładne dane wyjściowe OP , możesz dodać, machine_indented=${machine_indented/../ .}aby dodać dodatkowe miejsce przed pierwszym .. Jak powiedziałem, pedantyczny.
terdon

cześć Choroba, czy możesz wziąć pod uwagę uwagi Terdona w swojej odpowiedzi?
yael

@yael: Poprawienie rozwiązania powinno być teraz łatwe :-)
choroba

BTW - po co dodawać i przed> / dev / null?
yael

8

for m in $listjest zshskładnią. W bashnim będzie for i in "${list[@]}".

bashnie ma operatorów wypełniania. Możesz wypełniać printftylko spacjami, a nie dowolnymi znakami. zshma operatorów wypełniania.

#! /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

Wyściółka operator jest ${(r:25:)parameter}do prawej -Pad o długości 25 ze spacjami lub ${(r:25::string:)parameter}do prawej -Pad z dowolnym ciągiem zamiast przestrzeni.

Używamy również printf '%4s'do lewego- padu (x)ze spacjami. Moglibyśmy użyć ${(l:4:):-"($((++c)))"}zamiast tego. Istotną różnicą jest jednak to, że jeśli łańcuch ma więcej niż 4 znaki, ${(l)}skróci go, a zostanie przepełniony printf.


6

Specyfikator %sformatu może przyjmować precyzję ( %.20sna przykład) i tak jak w przypadku wyświetlania wartości zmiennoprzecinkowej z określoną precyzją ( %.4fna przykład), wynikiem będzie maksymalnie tyle znaków z podanego argumentu łańcucha.

Utwórz ciąg zawierający nazwę komputera i wystarczającą liczbę kropek, aby zabrakło kropek:

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

Wynik:

(1) vboxhost ........... CONNECTION OK
(2) ntp.stupi.se ....... CONNECTION OK
(3) example.com ........ CONNECTION OK
(4) nonexistant ........ CONNECTION FAIL

2

Z rzeczami skradzionymi z odpowiedzi @ 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 

2

Zrobiłbym to za pomocą fpingi awk. Niestety, awk„s printfnie może pad z kropek, tylko ze spacji lub zera, więc muszę napisać funkcję:

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

Używam w nawiasach 2-cyfrowej liczby zero-padded, aby format nie został zepsuty, jeśli jest 10-99 hostów $list(100+ nadal je zepsuje ). Alternatywą byłoby opóźnić drukowanie aż w END {}bloku i na / regexp-meczów / po prostu włóż hosta do jednej z trzech tablic, na przykład ok, fail, unknown. lub tylko jedna tablica asocjacyjna (np hosts[hostname]="OK".). Następnie możesz policzyć liczbę linii i użyć jej do określenia, jak szerokie powinno być pole licznika linii.

Zdecydowałem także, aby w wyniku rozróżniać nieznane hosty ( CONNECTION IMPOSSIBLE) i nieosiągalne hosty ( CONNECTION FAIL).

sort -k3Jest opcjonalne, to po prostu grupy wyjście przez fpingwynik ( „nazwa hosta jest żywy”, „nazwa hosta jest nieosiągalny” lub „nazwa hosta: Nazwa lub usługa nie znane”). Bez tego sortnieznane hosty zawsze pojawią się jako pierwsze na wyjściu. Po prostu sortbez -k3sortowania posortowane według nazwy hosta.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.