Pergunta

Eu tenho um que se parece com isso:

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]

Eu gostaria de criar um shell script que calcula a média dos 2º e 3º campos entre colchetes (840 e 0 no último exemplo). Uma questão ainda mais difícil: é possível obter a média do 3º campo apenas quando o último não é 0

Eu sei que eu poderia usar Ruby ou outra linguagem para criar um script, mas eu gostaria de fazê-lo em Bash. Qualquer boas sugestões sobre recursos ou sugestões em como criar um script como esse ajudaria.

Foi útil?

Solução

Postando a resposta I colado a você através de mensagens instantâneas, também aqui, apenas porque me faz tentar StackOverflow out:)

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

Outras dicas

Use bash e awk:

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

Exemplo de saída (para os dados originais):

avg2=2859.59, avg3=149.94

Claro, você não precisa usar cat, é incluído lá para legibilidade e para ilustrar o fato de que os dados de entrada pode vir de qualquer tubo; se você tiver que operar em um arquivo existente, sed -ne '...' file | ... executado diretamente.


Editar

Se você tem acesso a gawk (GNU awk), você pode eliminar a necessidade de sed da seguinte forma:

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

As mesmas observações re. cat aplicar.

Um pouco de explicação:

  • sed imprime apenas as linhas (combinação -n ... :p) que correspondem à expressão regular (linhas contendo INFO seguido por qualquer combinação de dígitos, espaços e vírgulas entre parêntesis rectos na extremidade da linha, permitindo espaços à direita e CR); Se qualquer um desses jogos de linha, só manter o que está entre colchetes (\1, correspondente ao que está entre \(...\) na expressão regular) antes de imprimir (:p)
    • sed linhas de saída vontade que se parecem com: 8541, 931, 0, 0
  • awk usa uma vírgula cercado por 0 ou mais espaços (-F ' *, *') como delimitadores de campo; corresponde $1 para a primeira coluna (por exemplo, 8541), $2 para o segundo, etc. ausente colunas contam como valor 0
    • no final, awk divide o acumuladores sum2 etc pelo número de registos processados, NR
  • gawk faz tudo de uma só vez; ele irá primeiro teste se cada linha corresponde a mesma expressão regular passada no exemplo anterior para sed (exceto que sed ao contrário, awk não requer um \ no fron os parênteses que delimitam áreas ou juros). Se os jogos de linha, o que está entre a rodada suportes acaba em um [1], que, em seguida, dividir usando o mesmo separador (uma vírgula cercado por qualquer número de espaços) e usar isso para acumular. Eu apresentei cnt vez de continuar a usar NR porque o número de registros NR processado pode ser maior do que o número real de registros relevantes (cnt) se não todas as linhas são do INFO ... [...comma-separated-numbers...] forma, o que não foi o caso com sed|awk desde sed garantiu que todas as linhas passadas para awk foram relevantes.

Use nawk ou / usr / XPG4 / bin / awk em Solaris .

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

Use 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top