
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 z
son, al final de cada iteración, exactamente y solo los últimos registros vistos hasta ahora para cada dirección IP.
Los índices de y
son, por tanto, las líneas exactas que deseamosnoimprimir.
Respuesta2
Guarde la línea completa (usándola $6
como índice de matriz) e END
itere 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