Imprima solo las líneas únicas que aparecen al final en el archivo de registro según la fecha/hora

Imprima solo las líneas únicas que aparecen al final en el archivo de registro según la fecha/hora

Estoy trabajando con un archivo de registro con el siguiente formato:

Oct 12 01:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 01:30:00 server program: 192.168.1.104 text for 1.104 
Oct 12 01:30:23 server program: 192.168.1.103 text for 1.103
Oct 12 01:32:39 server program: 192.168.1.101 text for 1.101 
Oct 12 02:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 02:30:00 server program: 192.168.1.104 text for 1.104
Oct 12 02:30:23 server program: 192.168.1.103 text for 1.103 
Oct 12 02:32:39 server program: 192.168.1.101 text for 1.101 

Necesito lograr esto:

Oct 12 02:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 02:30:00 server program: 192.168.1.104 text for 1.104
Oct 12 02:30:23 server program: 192.168.1.103 text for 1.103
Oct 12 02:32:39 server program: 192.168.1.101 text for 1.101

¿Cómo puedo enviar el nuevo resultado a un archivo? He probado esto:

awk '!_[$6]++ {a=$6} END{print a}' logfile

Pero no me da los resultados esperados. ¿Cómo puedo usar awk o sed para obtener solo las líneas únicas con la última vez que se vio la coincidencia de cadena o según la fecha/hora?

Respuesta1

Si va a hacer una segunda pasada (lo cual es bastante necesario), también puede almacenar solo números de línea en lugar de registros completos. Facilita la lógica.

awk 'NR == FNR {if (z[$6]) y[z[$6]]; z[$6] = FNR; next} !(FNR in y)' logfile logfile

Prueba de corrección:

Al final del procesamiento de cada línea, cada número de línea procesado hasta el momento escualquieraun valor en z,oun índice (no un valor) en y, pero nunca ambos.

Las líneas representadas por los valores en zson, al final de cada iteración, exactamente y solo los últimos registros vistos hasta ahora para cada dirección IP.

Los índices de yson, por tanto, las líneas exactas que deseamosnoimprimir.

Respuesta2

Guarde la línea completa (usándola $6como índice de matriz) e ENDitere sobre los elementos de la matriz:

awk '{z[$6]=$0};END{for (i in z) print z[i]}' logfile

Sin embargo, el resultado no se ordenará... Podrías hacer algo como:

awk '{z[$6]=NR" "$0};END{for (i in z) print z[i]}' logfile | sort -k1,1n | cut -f2-
### this space ^ is a literal TAB

que guarda la línea no. más el contenido de la línea para poder luego ordenar por número de línea.


Otras formas implican una segunda pasada para ordenarlo por fecha (ya que se trata de un registro), pero imprimirán entradas duplicadas si la entrada contiene líneas duplicadas (es decir, líneas enteras), por ejemplo, con grep:

awk '{z[$6]=$0};END{for (var in z) print z[var]}' logfile | grep -Fxf- logfile

o solo con awk:

awk 'NR==FNR{z[$6]=$0;next}
FNR==1{for (var in z) y[z[var]]}
$0 in y' logfile logfile

Respuesta3

Si tiene líneas solo del mismo día, puede manejar esto así:

sort -k6 -k3r logfile | uniq -f3 | sort -k3

Si tienes colas para más de un día, aún puedes utilizar este método básico, pero tu clasificación tendrá que ser mucho más sofisticada. El comando anterior sólo puede manejar registros de un día porque utiliza la parte de tiempo de la marca de tiempo (por ejemplo, 02:28:26) como proxy para toda la marca de tiempo.

Respuesta4

La lógica se vuelve más simple al invertir el archivo en línea

$ tac logfile | awk '!seen[$6]++' | tac
Oct 12 02:28:26 server program: 192.168.1.105 text for 1.105 
Oct 12 02:30:00 server program: 192.168.1.104 text for 1.104
Oct 12 02:30:23 server program: 192.168.1.103 text for 1.103 
Oct 12 02:32:39 server program: 192.168.1.101 text for 1.101 

información relacionada