Imprimir statistics de un file de text

Tengo un file de text (events.dat) como este a continuación (solo se muestra un extracto)

RepID12 01/01/2010 20:56:00 S10 RepID12 01/01/2010 20:56:00 S03 RepID20 01/01/2010 20:56:00 S17 RepID33 01/01/2010 20:56:00 S02 RepID33 01/01/2010 20:56:00 S18 RepID38 01/01/2010 20:56:00 S11 RepID39 01/01/2010 20:56:00 S20 RepID26 02/01/2010 01:39:00 S20 RepID29 02/01/2010 01:39:00 S16 RepID29 02/01/2010 01:39:00 S03 RepID22 02/01/2010 01:39:09 S01 RepID26 02/01/2010 01:39:09 S02 RepID40 02/01/2010 01:39:18 S02 RepID38 02/01/2010 01:39:09 S05 RepID31 02/01/2010 01:39:09 S06 RepID31 02/01/2010 01:39:09 S08 RepID09 02/01/2010 01:39:09 S09 RepID23 02/01/2010 01:39:18 S09 RepID19 02/01/2010 01:40:09 S09 RepID21 02/01/2010 01:40:18 S09 RepID28 02/01/2010 01:40:27 S09 RepID43 02/01/2010 01:40:09 S14 

y así sucesivamente, cubriendo events por un time total de 48 horas. Me gustaría imprimir solo las líneas cuando se encuentran más de 60 events por minuto.

Por ejemplo, con este command puedo contar cuántos events hay en 1 minuto específico:

 grep "02/01/2010 01:39" events.dat | wc -l 

y esto devolverá 60 (por ejemplo) que debería ser el número máximo de events / min.

¿Cómo puedo hacer lo mismo, pero verificando cada minuto durante las 48 horas completas e imprimo solo las líneas donde se encuentran más de 60 events / min? THX por adelantado

Con algo como esto puedes aislar los minutos disponibles:

 root@debian:# awk -F" " '{print $2" "$3}' b.txt |cut -f1-2 -d: |uniq 01/01/2010 20:56 02/01/2010 01:39 02/01/2010 01:40 02/01/2010 20:56 

A continuación, puede asignar una matriz con esos valores

Código revisado:

 readarray -t stamps < <(awk -F" " '{print $2" "$3}' b.txt |cut -f1-2 -d: |uniq) for stamp in "${stamps[@]}";do ev=$(grep "$stamp" b.txt |wc -l) echo "In $stamp found $ev events " #if [ "$ev" -gt 60 ]; then # do the stuff #fi done 

Salida:

 In 01/01/2010 20:56 found 7 events In 02/01/2010 01:39 found 11 events In 02/01/2010 01:40 found 4 events In 02/01/2010 20:56 found 7 events 

Idealmente, querría probar y procesar el file una sola vez y almacenar tan poco de él en la memory. En awk , podrías hacer:

 awk -vn=60 ' { t = $2 substr($3, 1, 5); if (t == last_t) { if (++lines > n) print else if (lines == n) print saved $0 else saved = saved $0 RS } else { saved = $0 RS lines = 1 last_t = t } }' < your-file 

Algunas ventajas con ese enfoque:

  • Eso está orientado al procesamiento de flujos. La input se procesa tan pronto como llega y la salida se emite lo antes posible (tan pronto como se haya visto la línea 60). Eso posibilita postprocesar el resultado en vivo del process (como en un tail -fn +1 log_file ).
  • solo ejecuta una invocación de un command ( awk ), por lo que será tan eficiente como pueda getse. El extremo opuesto sería ejecutar varios commands en un bucle . Lo más costoso en scripting de shell es generalmente bifurcar y ejecutar commands. Optimizar significa networkingucir eso tanto como sea posible.
  • solo almacenamos a lo sumo 60 líneas en la memory para que el uso de la memory esté vinculado (siempre que el tamaño de las líneas esté vinculado).
  • awk código awk se puede hacer muy legible y auto explicativo. Ahora, si el problema es el tamaño, también puedes hacerlo más corto y en una línea como

     awk '{t=$2substr($3,1,5);if(t==l){if(++i>n)print;else if(i==n)print s$0;else s=s$0RS}else{s=$0RS;i=1;l=t}}' n=60 file 

Esta no es la solución más eficiente, pero primero puede contar el número de events por cada minuto y luego grep su file para cada uno de estos minutos cuando el recuento es> = 60.

 sort -k 2,3 your_log_file \ | uniq -c -s 8 -w 16 \ | while read count _ date time _; do [ "$count" -ge 60 ] && grep -F " $date ${time%:*}" your_log_file done 

Notas:

  • en el ejemplo básico anterior, primero orderé tu file cronológicamente
  • las dos primeras líneas le darán la cantidad de events por minutos, si esta es la única información que le interesa.

Si su file está lleno de events, es probable que termine haciendo muchos grep s en él. Una mejor solución sería leer el file de logging secuencialmente y memorizar las líneas del último minuto. Cuando llegue al próximo minuto, imprima estas líneas si su número es mayor que 60. Vea la respuesta de Stéphane para una solución de este tipo.

 awk '{ print $2 " " $3 }' < input \ | cut -c1-16 \ | sort \ | uniq -c \ | awk '{ if ($1 > 60) print $2 }' 

es decir, get los campos de date y hora, quitar los segundos, orderar el resultado (NB: podría funcionar mejor si las dates estaban en formatting ISO), encontrar el recuento de cada combinación de date / hora única y luego imprimirlas con un conteo> 60