Domanda

Ne ho uno simile al seguente:

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]

Vorrei creare uno script di shell che calcola la media del 2 ° e 3 ° campo tra parentesi ( 840 e 0 nell'ultimo esempio). Una domanda ancora più difficile: è possibile ottenere la media del 3 ° campo solo quando l'ultimo non è 0 ?

So che potrei usare Ruby o un'altra lingua per creare uno script, ma mi piacerebbe farlo in Bash . Qualsiasi buon suggerimento su risorse o suggerimenti su come creare un tale script sarebbe di aiuto.

È stato utile?

Soluzione

Pubblicando la risposta che ho incollato anche su IM qui, solo perché mi fa provare StackOverflow :)

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

Pubblicando la risposta che ho incollato anche su IM qui, solo perché mi fa provare StackOverflow :)

<*>; $n++' < log

Altri suggerimenti

Usa bash e awk :

  

file cat | 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} '

Output di esempio (per i tuoi dati originali):

  

avg2 = 2859.59, avg3 = 149.94

Naturalmente, non è necessario utilizzare cat , è incluso lì per leggibilità e per illustrare il fatto che i dati di input possono provenire da qualsiasi pipe; se devi operare su un file esistente, esegui il file sed -ne '...' | ... direttamente.


Modifica

Se hai accesso a gawk (GNU awk), puoi eliminare la necessità di sed come segue:

  

file cat | 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} '

Stesse osservazioni relative a. cat si applica.

Un po 'di spiegazione:

  • sed stampa solo le righe (combinazione -n ...: p ) che corrispondono all'espressione regolare (righe contenenti INFO seguite da qualsiasi combinazione di cifre, spazi e virgole tra parentesi quadre alla fine della linea, tenendo conto degli spazi finali e CR); se una di queste righe corrisponde, mantieni solo ciò che è tra parentesi quadre ( \ 1 , corrispondente a ciò che è tra \ (... \) nell'espressione regolare) prima di stampare ( : p )
    • sed produrrà linee simili a: 8541, 931, 0, 0
  • awk utilizza una virgola circondata da 0 o più spazi ( -F '*, *' ) come delimitatori di campo; $ 1 corrisponde alla prima colonna (ad es. 8541), $ 2 alla seconda ecc. Le colonne mancanti contano come valore 0
    • alla fine, awk divide gli accumulatori sum2 ecc. per il numero di record elaborati, NR
  • gawk fa tutto in un colpo solo; testerà prima se ogni riga corrisponde alla stessa espressione regolare passata nell'esempio precedente a sed (tranne che a differenza di sed , awk non richiede un \ tra le parentesi tonde che delimitano aree o interessi). Se la linea corrisponde, ciò che si trova tra le parentesi tonde finisce in un [1], che poi dividiamo usando lo stesso separatore (una virgola circondata da un numero qualsiasi di spazi) e usiamo quello per accumulare. Ho introdotto cnt invece di continuare a usare NR perché il numero di record elaborati NR potrebbe essere maggiore del numero effettivo di record pertinenti ( cnt ) se non tutte le righe hanno il formato INFO ... [... virgola-separate-numeri ...] , che non era il caso di sed | awk poiché sed ha garantito che tutte le righe passate su awk erano pertinenti.

Usa nawk o / usr / xpg4 / bin / awk su 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top