Análisis de datos en columnas

Tengo algunos datos en columnas que me gustaría formatear un poco más. Se parece a esto:

$ getStats | grep ESTABLISHED | column -t all tcp 117.54.56.131:80 <- 10.42.100.211:63752 ESTABLISHED:ESTABLISHED all tcp 10.42.120.201:63752 -> 219.224.67.112:31180 -> 137.51.59.141:80 ESTABLISHED:ESTABLISHED all tcp 77.221.237.24:443 <- 10.42.100.117:59999 ESTABLISHED:ESTABLISHED 

Esencialmente antes de llamar a la column -t Quiero mover el estado TCP, 'ESTABLISHED: ESTABLISHED' más allá en la primera y tercera línea para que esté correctamente ubicado con la segunda línea. ¿Cómo voy a hacer esto? Usar awk y printf parece un poco complicado aquí. Básicamente, quiero alinear todas las columnas y alinear a la derecha solo la última columna.

El verdadero problema aquí es que el número de columnas no es igual . Tienes algunas líneas con seis columnas y algunas con ocho.

Entonces, lo que debe hacer es agregar un campo x-ésimo y y-ésto vacío donde faltan (x e y podrían ser 5 y 6, o tal vez 3 y 4).

Podrías hacerlo así:

 F="\\(\\S\\S*\\)\\s*\\s" # This is 0160, a nonbreaking space G=" " | sed -e "s/^$F$F$F$F$F$F*$/\\1 \\2 \\3 \\4 \\5 $G $G \\6/g" \ | column -t 

sed identifica esas líneas con solo seis campos, y agrega dos campos adicionales donde corresponda. Con lo anterior, obtengo

 all tcp 117.54.56.131:80 <- 10.42.100.211:63752   ESTABLISHED:ESTABLISHED all tcp 10.42.120.201:63752 -> 219.224.67.112:31180 -> 137.51.59.141:80 ESTABLISHED:ESTABLISHED all tcp 77.221.237.24:443 <- 10.42.100.117:59999   ESTABLISHED:ESTABLISHED 

EDIT 1:

Una forma podría ser algo como:

 getStats | grep ESTABLISHED | column -t | sed \ -e 's/\(<-\|->\)[ ]\+/\1 /g' \ -e 's/[ ]\+\([^ ]\+$\)/\t\1/' | column -t -s " " ^--- TAB all tcp 117.54.56.131:80 <- 10.42.100.211:63752 ESTABLISHED:ESTABLISHED all tcp 10.42.120.201:63752 -> 219.224.67.112:31180 -> 137.51.59.141:80 ESTABLISHED:ESTABLISHED all tcp 77.221.237.24:443 <- 10.42.100.117:59999 ESTABLISHED:ESTABLISHED 

Primero usar la column -t luego eliminar todos los espacios consecutivos después de <- y -> con un espacio, luego separar la última columna con tab y hacer una nueva column -t -s '<TAB>'

Si está en la línea de command: -s " Ctrl + V TAB " (también conocido como tab ) como separador de la column . Opcionalmente use tr para replace las tabs primero por espacios.

Configurando sed a una operación y omitiendo grep y algunas otras modificaciones:

 getStats | column -t | \ sed '/ESTABLISHED/!d;s/\(<-\|->\) */\1 /g;s/ *\([^ ]*\)$/\t \1/' | \ column -t -s " " ^--- TAB 

EDICION 2:

Aunque encuentras awk y printf desorderado, doy esto como una opción. Con este script, puedes decir:

 getStats | scrip_name ESTABLISHED 

Una ventaja es la flexibilidad para personalizar, etc.

De cualquier manera que uno lo mire uno tiene que analizar los datos dos veces o save meta sobre datos e imprimir al final.

En resumen, lo que hace es:

  • Registre el ancho máximo de cada columna.
  • Registre la cantidad máxima de columnas.
  • Guarde cada campo en una matriz en línea.
  • Al final, imprima cada campo pero use el ancho máximo para esa columna.
  • Llene hasta columnas máximas – 1 con espacios.
  • Imprimir el último campo

(La split entre awk -v pat="$1" ' y el rest del código solo se debe a resaltar el comentario HTML personalizado en esta página)

 #!/bin/bash # Argument 1 is what to match against. awk -v pat="$1" ' 
 # Iff match pat. $0 ~ pat { # Highest number of columns. if (NF > cols) cols = NF # Increment number of lines. ++nl # Number of fileds on this line. lines[nl] = NF for (i = 1; i <= NF; ++i) { # IFF not last field and # width of field is > current width of column, store it in wc_a. if (i < NF && (wc = length($i)) > wc_a[i]) wc_a[i] = wc # Save columns in array lines[LINE COLUMN]=FIELD_DATA. lines[nl,i] = $i } } END { # Loop lines. for (i = 1; i <= nl; ++i) { # Print all but last. for (j = 1; j < lines[i]; ++j) printf("%-*s ", wc_a[j], lines[i,j]) # Print "missing" columns. for (; j < cols; ++j) printf("%-*s ", wc_a[j], "") # Print last column field. printf("%s\n", lines[i,lines[i]]) } } ' "$2" # $2 is either file or empty: expect pipe. 

ANTIGUO:

Eliminado y encontrado aquí.

Aquí hay un pequeño script de Perl para lograr lo que desea:

 $ getStats | grep ESTABLISHED | \ perl -ne ' chomp @a; @a = split(" ",$_); map { print "$_," } @a[0..4]; if ($a[5] !~ m/>/) { map { print " , ,$_," } @a[5..$#a]; print "\n"; } else { map { print "$_," } @a[5..$#a]; print "\n"; } ' | column -t -s ',' 

Resultados en esta salida:

 all tcp 117.54.56.131:80 <- 10.42.100.211:63752 ESTABLISHED:ESTABLISHED all tcp 10.42.120.201:63752 -> 219.224.67.112:31180 -> 137.51.59.141:80 ESTABLISHED:ESTABLISHED all tcp 77.221.237.24:443 <- 10.42.100.117:59999 ESTABLISHED:ESTABLISHED 

Tomé un enfoque ligeramente diferente con su column -t y modifiqué mi salida de Perl para que introdujera una coma "," entre cada campo. Entonces la salida antes del command de la columna `se ve así:

 all,tcp,117.54.56.131:80,<-,10.42.100.211:63752, , ,ESTABLISHED:ESTABLISHED, all,tcp,10.42.120.201:63752,->,219.224.67.112:31180,->,137.51.59.141:80,ESTABLISHED:ESTABLISHED, all,tcp,77.221.237.24:443,<-,10.42.100.117:59999, , ,ESTABLISHED:ESTABLISHED, 

La column -t -s ',' luego convence a la column para que se divida en los caracteres del separador, lo cual me resulta más fácil de manejar que el simple espacio en blanco.

La introducción de las comas por cada línea me parece un poco chistosa, pero cumple su function, esto podría simplificarse aún más, pero es una solución que funciona.