Выравнивание вывода сценария оболочки Bash

29

Мой сценарий:

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

Выводит ли информация следующим образом:

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

который я хотел бы очистить, чтобы получить что-то вроде этого:

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
источник

Ответы:

45

Используйте printfдля форматирования вывода (это также более переносимо, чемecho ). Я бы также сохранил реальное значение цветовых escape-последовательностей вместо того, чтобы хранить их в форме, которая требует расширения 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"

%-15sявляется спецификация формата , что подушечки строки с пробелами справа , так как длина (в количестве символов в zshи fishи байты в большинстве других оболочек / Printf ) , чтобы быть по крайней мере 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|

С усечением:

$ 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|

Другие утилиты для форматирования текста в столбцах включают POSIXexpand :

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

(здесь расширение символа TAB ( \t) с помощью табуляции через каждые 30 столбцов)

Или BSDcolumn или POSIXpr :

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

(здесь выводится по 2 столбцам шириной 36 столбцов (см. -wопцию изменения ширины страницы по умолчанию, равной 72)).

или BSDrs :

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

(например column, не начнет выводить, пока не прочитает все входные данные).

Или GNUcolumns :

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

zshтакже есть некоторые флаги расширения параметров для заполнения строк: ${(l:15:)hostname}для заполнения слева и ${(r:15:)hostname}для заполнения справа (с усечением). При развертывании подсказок (как в подсказках или в print -Pили как включено в раскрытиях параметров с %флагом) он также поддерживает %F{green}вывод цветов, поэтому вы можете сделать:

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

Или:

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

Несмотря на то, что содержимое $hostnameзатем будет также подвергаться быстрому расширению, что могло бы стать уязвимостью внедрения команд, если содержимое $hostnameне было бы под вашим контролем (как в hostname='%<a[`reboot`]<')

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

Просто с columnкомандой:

yourscript.sh | column -t

Выход:

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
RomanPerekhrest
источник
прошу прощения за глупый вопрос, но где я должен поставить эту команду?
pijaaa
@pijaaa, посмотри мое обновление, труба с выходом твоего скрипта
RomanPerekhrest
10
Обратите внимание, что column(команда BSD, также портированная на Linux и встречающаяся по умолчанию в некоторых дистрибутивах, не путать с GNU columns), должна будет прочитать весь ввод, прежде чем он сможет что-то начать выводить, так как он должен вычислять ширину столбцов на основе на самом широком.
Стефан
3

Обновите ваш скрипт, чтобы вставить установленный номер в \t(вкладки), куда вы хотите вставить столбец.

Вывод чего-то похожего на следующее даст вам необходимое выравнивание:

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
источник
3
Стоит добавить короткий пример, основанный на сценарии в вопросе ...
Стивен Китт,
@StephenKitt ty Стивен, я пытался понять, как сделать это больше, чем просто одной строкой, и это, честно говоря, мне не пришло в голову!
djsmiley2k - CoW
3
Вы заметите, что с вкладками по умолчанию каждые 8 ​​столбцов printf 'Network %s\t: Online\n' 8.8.8.8 192.168.122.123не выравнивается должным образом. Вы можете обойти это, используя, expandчтобы расширить вкладки с другой табуляции, как показано в моем ответе.
Стефан
Пожалуйста, примите это как ответ, нажав на значок галочки.
djsmiley2k - CoW
0

Для отображения даже лучше, чем @Roman

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

Затем добавьте \tв каждую строку, чтобы разделить его на столбец.

Emidomenge
источник