Alinhamento da saída do script do shell Bash

29

Meu script:

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

Está produzindo informações como esta:

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

que eu gostaria de limpar para obter algo assim:

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
fonte

Respostas:

45

Use printfpara formatar a saída (também é mais portátil queecho ). Também armazenaria o valor real das seqüências de escape de cores em vez de armazená-las de uma forma que exija expansão por 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é uma especificação de formato que as almofadas das cordas com espaços sobre a direita de modo como o comprimento (em número de caracteres em zshe fishe bytes de mais outros escudos / printf ) para ser, pelo menos, 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|

Com truncamento:

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

Outros utilitários para formatar texto em colunas incluem POSIXexpand :

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

(aqui expandindo o caractere TAB ( \t) com tab stops a cada 30 colunas)

Ou BSDcolumn ou POSIXpr :

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

(aqui exibindo 2 colunas de 36 colunas de largura (consulte a -wopção para alterar a largura da página do padrão de 72)).

ou BSDrs :

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

(o tipo columnnão começará a produzir até que tenha lido toda a entrada).

Ou GNUcolumns :

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

zshtambém possui alguns sinalizadores de expansão de parâmetro para preenchimento de cadeia de caracteres: ${(l:15:)hostname}para preenchimento esquerdo e ${(r:15:)hostname}para preenchimento direito (com truncamento). Na expansão rápida (como em prompts ou dentro print -Pou conforme habilitado nas expansões de parâmetro com o %sinalizador), ele também suporta %F{green}a saída em cores, para que você possa:

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

Ou:

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

Embora o conteúdo de $hostnametambém esteja sujeito a expansão imediata, o que constituiria uma vulnerabilidade de injeção de comando se o conteúdo de $hostnamenão estivesse sob seu controle (como em hostname='%<a[`reboot`]<')

Stéphane Chazelas
fonte
35

Simplesmente com o columncomando:

yourscript.sh | column -t

A saída:

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
fonte
desculpe pela pergunta estúpida, mas onde devo colocar esse comando?
Pijaaa 5/10
@pijaaa, veja minha atualização, canalize com a saída do seu script #
RomanPerekhrest 5/17
10
Observe que column(um comando BSD, também portado para Linux e encontrado por padrão em algumas distribuições, não deve ser confundido com o GNU columns) precisará ler toda a entrada antes que possa começar a produzir algo, pois precisa calcular a largura das colunas com base em no mais largo.
Stéphane Chazelas
3

Atualize seu script para inserir um número definido para \t(tabs) onde você deseja tabular para uma coluna.

A saída de algo semelhante ao seguinte forneceria o alinhamento necessário:

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
fonte
3
Seria pena acrescentar um pequeno exemplo baseado no roteiro na questão ...
Stephen Kitt
@ StephenKitt ty Stephen, eu estava tentando descobrir como torná-lo mais do que apenas uma linha, e isso honestamente não me ocorreu!
djsmiley2k - Cow
3
Você notará que, com as paradas de tabulação padrão a cada 8 colunas, printf 'Network %s\t: Online\n' 8.8.8.8 192.168.122.123não se alinha adequadamente. Você pode contornar isso usando expandpara expandir as guias com uma parada de guia diferente, como mostrado na minha resposta.
Stéphane Chazelas 5/17/17
Sinta-se à vontade para aceitar isso como resposta, clicando no ícone de visto.
djsmiley2k - Cow
0

Para exibir ainda melhor que o @Roman

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

Em seguida, adicione \tcada linha para dividi-la em coluna.

Emidomenge
fonte