Wyrównanie danych wyjściowych skryptu powłoki Bash

29

Mój skrypt:

date
echo -e "${YELLOW}Network check${NC}\n\n"

while read hostname
do

ping -c 1 "$hostname" > /dev/null 2>&1 &&

echo -e "Network $hostname : ${GREEN}Online${NC}" ||
echo -e "${GRAY}Network $hostname${NC} : ${RED}Offline${NC}"

done < list.txt
        sleep 30
clear
done

Czy wyprowadza takie informacje:

Network 10.x.xx.xxx : Online   
Network 10.x.xx.xxx : Offline   
Network 10.x.xx.xxx : Offline   
Network 10.x.xx.xxx : Offline   
Network 10.x.xx.x : Online   
Network 139.xxx.x.x : Online   
Network 208.xx.xxx.xxx : Online   
Network 193.xxx.xxx.x : Online

które chciałbym posprzątać, aby uzyskać coś takiego:

Network 10.x.xx.xxx       : Online  
Network 10.x.xx.xxx       : Offline   
Network 10.x.xx.xxx       : Offline    
Network 10.x.xx.x         : Online    
Network 139.xxx.x.x       : Online  
Network 208.xx.xxx.xxx    : Online    
Network 193.xxx.xxx.x     : Online  
Network 193.xxx.xxx.xxx   : Offline
pijaaa
źródło

Odpowiedzi:

45

Służy printfdo formatowania danych wyjściowych (jest również bardziej przenośny niżecho ). Chciałbym również przechowywać rzeczywistą wartość sekwencji zmiany koloru zamiast przechowywać je w formie, która wymaga rozszerzenia echo.

RED=$(tput setaf 1) GREEN=$(tput setaf 2) YELLOW=$(tput setaf 3)
NC=$(tput sgr0) 
online="${GREEN}online$NC" offline="${RED}offline$NC"

ping -c 1 "$hostname" > /dev/null 2>&1 && state=$online || state=$offline
printf 'Network %-15s: %s\n' "$hostname" "$state"

%-15sjest specyfikacją formatu że klocki struny ze spacjami po prawej stronie tak jak długość (w liczbie znaków w zshi fishi bajtów w większości innych skorup / printf ) musi wynosić co najmniej 15.

$ printf '|%-4s|\n' a ab abc abcd abcde
|a   |
|ab  |
|abc |
|abcd|
|abcde|
 printf '|%4s|\n' a ab abc abcd abcde
|   a|
|  ab|
| abc|
|abcd|
|abcde|

Z obcięciem:

$ printf '|%.4s|\n' a ab abc abcd abcde
|a|
|ab|
|abc|
|abcd|
|abcd|
$ printf '|%4.4s|\n' a ab abc abcd abcde
|   a|
|  ab|
| abc|
|abcd|
|abcd|
$ printf '|%-4.4s|\n' a ab abc abcd abcde
|a   |
|ab  |
|abc |
|abcd|
|abcd|

Inne narzędzia do formatowania tekstu w kolumnach obejmują POSIXexpand :

printf 'Network %s\t: %s\n' "$hostname" "$state" | expand -t 30

(tutaj rozwijanie znaku TAB ( \t) z tabulatorami co 30 kolumn)

Lub BSDcolumn lub POSIXpr :

printf 'Network %s\n: %s\n' "$hostname" "$state" | pr -at2

(tutaj wyjście na 2 36-kolumnowych kolumnach (patrz -wopcja zmiany szerokości strony z domyślnej 72)).

lub BSDrs :

{
   while...
      printf 'Network %s\n: %s\n' "$hostname" "$state"
   done
} | rs -e 0 2

(jak columnnie zacznie wypisywać, dopóki nie przeczyta wszystkich danych wejściowych).

Lub GNUcolumns :

printf 'Network %s\n: %s\n' "$hostname" "$state" | columns -w 25 -c 2

zshma również kilka flag rozszerzania parametrów dla dopełniania łańcucha: ${(l:15:)hostname}do dopełniania po lewej i ${(r:15:)hostname}do dopełniania po prawej (z obcięciem). W szybkim rozszerzaniu (jak w monitach lub w print -Plub tak, jak jest to włączone w rozszerzeniach parametrów z %flagą), obsługuje on również %F{green}wyświetlanie kolorów, dzięki czemu możesz:

online='%F{green}online%f'
printf '%s\n' "Network ${(r:15:)hostname}: ${(%)online}"

Lub:

print -rP "Network ${(r:15:)hostname}: $online"

Chociaż treść $hostnametego również podlegałaby szybkiemu rozszerzeniu, co stanowiłoby podatność na wstrzykiwanie poleceń, gdyby treść $hostnamenie była pod twoją kontrolą (jak w hostname='%<a[`reboot`]<')

Stéphane Chazelas
źródło
35

Po prostu z columnpoleceniem:

yourscript.sh | column -t

Wyjście:

Network  10.x.xx.xxx     :  Online
Network  10.x.xx.xxx     :  Offline
Network  10.x.xx.xxx     :  Offline
Network  10.x.xx.xxx     :  Offline
Network  10.x.xx.x       :  Online
Network  139.xxx.x.x     :  Online
Network  208.xx.xxx.xxx  :  Online
Network  193.xxx.xxx.x   :  Online
Roman Perekhrest
źródło
przepraszam za głupie pytanie, ale gdzie powinienem umieścić to polecenie?
pijaaa
@pijaaa, zobacz moją aktualizację, potok z wyjściem skryptu
RomanPerekhrest
10
Zauważ, że column(polecenie BSD, również przeniesione do Linuksa i domyślnie znalezione w niektórych dystrybucjach, których nie należy mylić z GNU columns) będzie musiało przeczytać całe dane wejściowe, zanim zacznie coś wypisywać, ponieważ musi obliczyć szerokość kolumn na podstawie w najszerszym.
Stéphane Chazelas,
3

Zaktualizuj skrypt, aby wstawić liczbę ustawioną na \t(tabulatory), w której chcesz tabulować do kolumny.

Wyprowadzenie czegoś podobnego do następującego dałoby wymagane wyrównanie:

Network 10.x.xx.xxx\t: Online   
Network 10.x.xx.xxx\t: Offline   
Network 10.x.xx.xxx\t: Offline   
Network 10.x.xx.xxx\t: Offline   
Network 10.x.xx.x\t: Online   
Network 139.xxx.x.x\t: Online   
Network 208.xx.xxx.xxx\t: Online   
Network 193.xxx.xxx.x\t: Online
djsmiley2k - CoW
źródło
3
Warto dodać krótki przykład oparty na skrypcie w pytaniu ...
Stephen Kitt
@StephenKitt ty Stephen, starałem się wymyślić, jak zrobić więcej niż jedną linię, a to szczerze nie przyszło mi do głowy!
djsmiley2k - CoW
3
Zauważysz, że przy domyślnych tabstopsach co 8 kolumn printf 'Network %s\t: Online\n' 8.8.8.8 192.168.122.123nie wyrówna się prawidłowo. Możesz obejść ten problem, korzystając expandz rozwijania kart z innym tabulatorem, jak pokazano w mojej odpowiedzi.
Stéphane Chazelas,
Możesz zatem zaakceptować to jako odpowiedź, klikając ikonę zaznaczenia.
djsmiley2k - CoW
0

Aby wyświetlić nawet lepiej niż @Roman

yourscript.sh | column -t -s $'\t'

Następnie dodaj \tw każdym wierszu, aby podzielić go na kolumnę.

Emidomenge
źródło