Alignement de la sortie du script shell Bash

29

Mon 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

Génère des informations comme ceci:

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 je voudrais nettoyer pour obtenir quelque chose comme ça:

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
la source

Réponses:

45

Utilisez printfpour formater la sortie (c'est aussi plus portable queecho ). Je voudrais également stocker la valeur réelle des séquences d'échappement de couleur au lieu de les stocker sous une forme qui nécessite une expansion par 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"

%-15sest une spécification de format qui remplit les chaînes avec des espaces à droite afin que la longueur (en nombre de caractères dans zshet fishet octets dans la plupart des autres shells / printf ) soit d'au moins 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|

Avec troncature:

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

Les autres utilitaires pour formater le texte dans les colonnes incluent POSIXexpand :

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

(en développant ici le caractère TAB ( \t) avec des tabulations toutes les 30 colonnes)

Ou BSDcolumn ou POSIXpr :

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

(ici, sortie sur 2 colonnes de 36 colonnes de large (voir l' -woption pour changer la largeur de page par défaut de 72)).

ou BSDrs :

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

(comme columnne commencera pas la sortie tant qu'il n'aura pas lu toutes les entrées).

Ou GNUcolumns :

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

zsha également quelques drapeaux d'extension de paramètre pour le remplissage de chaîne: ${(l:15:)hostname}pour le remplissage de gauche et ${(r:15:)hostname}pour le remplissage de droite (avec troncature). Dans l'expansion des invites (comme dans les invites ou dans print -Pou comme activé dans les extensions de paramètres avec l' %indicateur), il prend également en charge %F{green}la sortie couleur, vous pouvez donc faire:

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

Ou:

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

Bien que le contenu de $hostnamesoit alors soumis à une expansion rapide, ce qui constituerait une vulnérabilité d'injection de commande si le contenu de $hostnamen'était pas sous votre contrôle (comme dans hostname='%<a[`reboot`]<')

Stéphane Chazelas
la source
35

Simplement avec columncommande:

yourscript.sh | column -t

Le résultat:

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
la source
Je suis désolé pour une question stupide, mais où dois-je mettre cette commande?
pijaaa
@pijaaa, voir ma mise à jour, pipe avec la sortie de votre script
RomanPerekhrest
10
Notez que column(une commande BSD, également portée sur Linux et trouvée par défaut sur certaines distributions, à ne pas confondre avec GNU columns) devra lire l'intégralité de l'entrée avant de pouvoir commencer à produire quelque chose car elle doit calculer la largeur des colonnes en fonction sur le plus large.
Stéphane Chazelas
3

Mettez à jour votre script pour insérer un nombre défini dans \t(onglets) à l'endroit où vous souhaitez accéder à une colonne.

La sortie de quelque chose de similaire à ce qui suit vous donnerait l'alignement requis:

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
la source
3
Il vaudrait la peine d'ajouter un court exemple basé sur le script de la question ...
Stephen Kitt
@StephenKitt ty Stephen, j'essayais de comprendre comment faire plus d'une ligne, et cela ne m'est pas venu à l'esprit!
djsmiley2k - CoW
3
Vous remarquerez qu'avec les tabstops par défaut toutes les 8 colonnes, printf 'Network %s\t: Online\n' 8.8.8.8 192.168.122.123ne s'aligne pas correctement. Vous pouvez contourner cela en utilisant expandpour développer les onglets avec un taquet de tabulation différent, comme indiqué dans ma réponse.
Stéphane Chazelas
N'hésitez pas à accepter cela comme réponse, en cliquant sur l'icône de coche.
djsmiley2k - CoW
0

Pour afficher encore mieux que @Roman

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

Ajoutez ensuite \tchaque ligne pour la diviser en colonne.

Emidomenge
la source