Alinhamento de saída do script de shell Bash

21

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

A saída de informações é assim:

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 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
    
por pijaaa 05.10.2017 / 10:12

3 respostas

38

Use printf para formatar a saída (também é mais portátil que echo ). Também armazenaria o valor real das seqüências de escape de cores em vez de armazená-las em um formato que requer 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 preenche as strings com espaços à direita, assim como o comprimento (em número de caracteres em zsh e fish e bytes em a maioria dos outros shells / printf ) deve ter 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 POSIX expand :

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

(aqui expandindo o caractere TAB ( \t ) com paradas de tabulação a cada 30 colunas)

Ou BSD column ou POSIX pr :

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

(aqui produzindo em 2 colunas de 36 colunas de largura (veja a opção -w para mudar a largura da página do padrão de 72)).

ou BSD rs :

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

(como column não inicia a saída até ler toda a entrada).

Ou GNU columns :

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

zsh também possui alguns sinalizadores de expansão de parâmetro para preenchimento de string: ${(l:15:)hostname} para preenchimento esquerdo e ${(r:15:)hostname} para preenchimento direito (com truncamento). Em expansão de prompt (como em prompts ou em print -P ou como habilitado em expansões de parâmetro com o % flag), ele também suporta %F{green} para saída de cores, então você pode fazer:

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 $hostname também esteja sujeito a pronta expansão,  o que constituiria uma vulnerabilidade de injeção de comando se o conteúdo de $hostname não estivesse sob seu controle (como em hostname='%<a['reboot']<' )

    
por 05.10.2017 / 10:20
32

Simplesmente com o comando column :

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
    
por 05.10.2017 / 10:16
3

Atualize seu script para inserir um número definido em \t (guias) onde você deseja sair de 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
    
por 05.10.2017 / 15:47