Pregunta

Tengo una que se parece a esto:

I, [2009-03-04T15:03:25.502546 #17925]  INFO -- : [8541, 931, 0, 0]
I, [2009-03-04T15:03:26.094855 #17925]  INFO -- : [8545, 6678, 0, 0]
I, [2009-03-04T15:03:26.353079 #17925]  INFO -- : [5448, 1598, 185, 0]
I, [2009-03-04T15:03:26.360148 #17925]  INFO -- : [8555, 1747, 0, 0]
I, [2009-03-04T15:03:26.367523 #17925]  INFO -- : [7630, 278, 0, 0]
I, [2009-03-04T15:03:26.375845 #17925]  INFO -- : [7640, 286, 0, 0]
I, [2009-03-04T15:03:26.562425 #17925]  INFO -- : [5721, 896, 0, 0]
I, [2009-03-04T15:03:30.951336 #17925]  INFO -- : [8551, 4752, 1587, 1]
I, [2009-03-04T15:03:30.960007 #17925]  INFO -- : [5709, 5295, 0, 0]
I, [2009-03-04T15:03:30.966612 #17925]  INFO -- : [7252, 4928, 0, 0]
I, [2009-03-04T15:03:30.974251 #17925]  INFO -- : [8561, 4883, 1, 0]
I, [2009-03-04T15:03:31.230426 #17925]  INFO -- : [8563, 3866, 250, 0]
I, [2009-03-04T15:03:31.236830 #17925]  INFO -- : [8567, 4122, 0, 0]
I, [2009-03-04T15:03:32.056901 #17925]  INFO -- : [5696, 5902, 526, 1]
I, [2009-03-04T15:03:32.086004 #17925]  INFO -- : [5805, 793, 0, 0]
I, [2009-03-04T15:03:32.110039 #17925]  INFO -- : [5786, 818, 0, 0]
I, [2009-03-04T15:03:32.131433 #17925]  INFO -- : [5777, 840, 0, 0]

Me gustaría crear un script de shell que calcule el promedio de los campos 2 y 3 entre corchetes ( 840 y 0 en el último ejemplo). Una pregunta aún más difícil: ¿es posible obtener el promedio del tercer campo solo cuando el último no es 0 ?

Sé que podría usar Ruby u otro idioma para crear un script, pero me gustaría hacerlo en Bash . Cualquier buena sugerencia sobre recursos o sugerencias sobre cómo crear un script de este tipo ayudaría.

¿Fue útil?

Solución

Enviando la respuesta que te pegué a través de IM aquí también, solo porque me hace probar StackOverflow out :)

# replace $2 with the column you want to avg; 
awk '{ print $2 }' | perl -ne 'END{ printf "%.2f\n", $total/$n }; chomp; $total+= 

Enviando la respuesta que te pegué a través de IM aquí también, solo porque me hace probar StackOverflow out :)

<*>; $n++' < log

Otros consejos

Utilice bash y awk :

  

cat file | sed -ne 's: ^. * INFO. * \ [\ ([0-9,] * \) \] [\ r] * $: \ 1: p' | awk -F '*, *' '{sum2 + = $ 2; sum3 + = $ 3} FIN {if (NR > 0) printf " avg2 =%. 2f, avg3 =%. 2f \ n " ;, sum2 / NR, sum3 / NR} '

Salida de muestra (para sus datos originales):

  

avg2 = 2859.59, avg3 = 149.94

Por supuesto, no es necesario que utilice cat , se incluye para legibilidad y para ilustrar el hecho de que los datos de entrada pueden provenir de cualquier canalización; si tiene que operar con un archivo existente, ejecute el archivo sed -ne '...' | ... directamente.


EDIT

Si tiene acceso a gawk (GNU awk), puede eliminar la necesidad de sed de la siguiente manera:

  

cat file | gawk '{if (match ($ 0, /.*INFO.*\\\\\\\\\\\\\\)] [] [\ r] * $ /, a)) {cnt ++; dividir (a [1], b, / *, * /); sum2 + = b [2]; sum3 + = b [3]}} END {if (cnt > 0) printf " avg2 =%. 2f, avg3 =%. 2f \ n " ;, sum2 / cnt, sum3 / cnt} '

Las mismas observaciones re. cat se aplica.

Un poco de explicación:

  • sed solo imprime líneas (combinación -n ...: p ) que coinciden con la expresión regular (líneas que contienen INFO seguidas de cualquier combinación de dígitos, espacios y comas entre corchetes al final de la línea, permitiendo los espacios finales y CR); si alguna de estas líneas coincide, solo mantenga lo que está entre los corchetes ( \ 1 , correspondiente a lo que hay entre \ (... \) en la expresión regular) antes de imprimir ( : p )
    • sed emitirá líneas que parecen: 8541, 931, 0, 0
  • awk usa una coma rodeada por 0 o más espacios ( -F '*, *' ) como delimitadores de campo; $ 1 corresponde a la primera columna (por ejemplo, 8541), $ 2 a la segunda, etc. Las columnas que faltan cuentan como valor 0
    • al final, awk divide los acumuladores sum2 etc. por el número de registros procesados, NR
  • gawk hace todo de una vez; primero comprobará si cada línea coincide con la misma expresión regular pasada en el ejemplo anterior para sed (excepto que a diferencia de sed , awk no requiere un \ frente a los paréntesis redondos que delimitan áreas o intereses). Si la línea coincide, lo que está entre los paréntesis redondos termina en un [1], que luego dividimos usando el mismo separador (una coma rodeada por cualquier número de espacios) y lo usamos para acumular. Introduje cnt en lugar de seguir usando NR porque el número de registros procesados ?? NR puede ser mayor que el número real de registros relevantes ( cnt ) si no todas las líneas tienen el formato INFO ... [... comas-separados-numbers ...] , que no fue el caso con sed | awk desde sed garantizó que todas las líneas pasadas a awk eran relevantes.

Use nawk oro / usr / xpg4 / bin / awk donde Solaris .

awk -F'[],]' 'END { 
  print s/NR, t/ct 
  }  
{ 
  s += $(NF-3) 
  if ($(NF-1)) {
    t += $(NF-2)
    ct++
    }
  }' infile

Usa Python

logfile= open( "somelogfile.log", "r" )
sum2, count2= 0, 0
sum3, count3= 0, 0
for line in logfile:
    # find right-most brackets
    _, bracket, fieldtext = line.rpartition('[')
    datatext, bracket, _ = fieldtext.partition(']')
    # split fields and convert to integers
    data = map( int, datatext.split(',') )
    # compute sums and counts
    sum2 += data[1]
    count2 += 1
    if data[3] != 0:
        sum3 += data[2]
        count3 += 1
logfile.close()

print sum2, count2, float(sum2)/count2
print sum3, count3, float(sum3)/count3
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top