Alineación de salida de script de shell Bash

29

Mi guión:

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á generando información 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 me gustaría limpiar para obtener algo como esto:

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
fuente

Respuestas:

45

Úselo printfpara formatear la salida (también es más portátil queecho ). También almacenaría el valor real de las secuencias de escape de color en lugar de almacenarlas en una forma que requiera expansión 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"

%-15ses una especificación de formato que rellena las cadenas con espacios a la derecha para que la longitud (en número de caracteres en zshy fishy bytes en la mayoría de los demás shells / printf ) sea de al 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|

Con truncamiento:

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

Otras utilidades para formatear texto en columnas incluyen POSIXexpand :

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

(aquí expandiendo el carácter TAB ( \t) con tabulaciones cada 30 columnas)

O BSDcolumn o POSIXpr :

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

(aquí se imprime en 2 columnas de 36 columnas de ancho (vea la -wopción para cambiar el ancho de página del valor predeterminado de 72)).

o BSDrs :

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

(como columnno comenzará a salir hasta que haya leído toda la entrada).

O GNUcolumns :

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

zshtambién tiene algunos indicadores de expansión de parámetros para el relleno de cadena: ${(l:15:)hostname}para el relleno izquierdo y ${(r:15:)hostname}para el relleno derecho (con truncamiento). En la expansión rápida (como en las solicitudes o en print -Po como habilitado en las expansiones de parámetros con el %indicador), también admite %F{green}la salida de color, por lo que puede hacer:

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

O:

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

Aunque el contenido de $hostnameentonces también estaría sujeto a una rápida expansión, lo que constituiría una vulnerabilidad de inyección de comando si el contenido de $hostnameno estuviera bajo su control (como en hostname='%<a[`reboot`]<')

Stéphane Chazelas
fuente
35

Simplemente con columncomando:

yourscript.sh | column -t

La salida:

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
fuente
Lamento la estúpida pregunta, pero ¿dónde debo poner ese comando?
pijaaa
@pijaaa, mira mi actualización, canaliza con la salida de tu script
RomanPerekhrest
10
Tenga en cuenta que column(un comando BSD, también portado a Linux y encontrado por defecto en algunas distribuciones, que no debe confundirse con GNU columns) necesitará leer toda la entrada antes de que pueda comenzar a generar algo, ya que necesita calcular el ancho de las columnas en función en el más ancho
Stéphane Chazelas
3

Actualice su secuencia de comandos para insertar un número establecido en \t(pestañas) donde desee tabular a una columna.

Mostrar algo similar a lo siguiente le daría la alineación requerida:

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 - Vaca
fuente
3
Valdría la pena añadir un breve ejemplo basado en el guión en la pregunta ...
Stephen Kitt
@StephenKitt ty Stephen, estaba tratando de descubrir cómo hacer que sea más que una sola línea, ¡y esto honestamente no se me ocurrió!
djsmiley2k - CoW
3
Notarás que con las pestañas predeterminadas cada 8 columnas, printf 'Network %s\t: Online\n' 8.8.8.8 192.168.122.123no se alinean correctamente. Podría solucionarlo utilizando expandpara expandir las pestañas con un tabulador diferente como se muestra en mi respuesta.
Stéphane Chazelas
Siéntase libre de aceptar esto como la respuesta haciendo clic en el ícono de marca.
djsmiley2k - CoW
0

Para mostrar incluso mejor que @Roman

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

Luego agregue \tcada línea para dividirla en una columna.

Emidomenge
fuente