2009-03-04 15 views
1

Ich habe ein, das wie folgt aussieht:So führen Berechnung über eine Log-Datei

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] 

Ich möchte ein Shell-Skript erstellen, die den Mittelwert der 2. und 3. Felder in Klammern berechnet (840 und 0 im letzten Beispiel). Eine noch schwierigere Frage: Ist es möglich, den Durchschnitt des 3. Feldes nur zu bekommen, wenn der letzte nicht 0 ist?

Ich weiß, ich könnte Ruby oder eine andere Sprache verwenden, um ein Skript zu erstellen, aber ich möchte es in Bash tun. Gute Vorschläge zu Ressourcen oder Tipps zum Erstellen eines solchen Skripts wären hilfreich.

+0

Es wäre trivial sein, dies in awk zu tun. Zählt das als "macht es in bash"? – Eddie

Antwort

1

Buchung der Antwort, die ich hier zu Ihnen über IM geklebt, nur weil es mich macht Stackoverflow ausprobieren :)

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

Verwenden bash und 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 }'

Beispielausgabe (für die Originaldaten):

avg2=2859.59, avg3=149.94

Natürlich müssen Sie nicht cat verwenden, es ist dort für die Lesbarkeit enthalten und um die Tatsache zu veranschaulichen, dass Eingabedaten von jeder Pipe kommen können; Wenn Sie eine vorhandene Datei bearbeiten müssen, führen Sie sed -ne '...' file | ... direkt aus.


EDIT

Wenn Sie Zugriff auf gawk (GNU awk) haben, können Sie die Notwendigkeit sed beseitigen wie folgt:

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

Gleiche Bemerkungen Re. cat gelten.

Ein wenig Erläuterung:

  • sed druckt nur Zeilen aus (-n ... :p Kombination), die die regulären Ausdruck (Zeilen enthalten INFO durch eine beliebige Kombination von Ziffern, Leerstellen und Komma zwischen eckigen Klammern am Ende gefolgt Übereinstimmung von die Linie, die nachstehende Leerzeichen und CR zulässt); wenn eine solche Linie übereinstimmt, halten nur das, was zwischen den eckigen Klammern ist (\1, entsprechend, was zwischen \(...\) im regulären Ausdruck) vor dem Drucken (:p)
    • sed Willen Ausgangsleitungen, die wie folgt aussehen: 8541, 931, 0, 0
  • awk verwendet ein Komma umgeben von 0 oder mehr Leerzeichen (-F ' *, *') als Feldtrennzeichen; $1 entspricht der ersten Spalte (z. B. 8541), $2 der zweiten usw.Fehlende Spalten als Wert zählen 0
    • am Ende teilt awk die Akkumulatoren sum2 usw. durch die Anzahl der Datensätze verarbeitet, NR
  • gawk tut alles auf einen Schlag; Zuerst wird getestet, ob jede Zeile mit demselben regulären Ausdruck übereinstimmt, der im vorherigen Beispiel an sed übergeben wurde (außer dass im Gegensatz zu sed, awk keine \ in den runden Klammern benötigt wird, die Bereiche oder Interessenbereiche begrenzen). Wenn die Zeile übereinstimmt, endet das, was zwischen den runden Klammern steht, in [1], die wir dann unter Verwendung des gleichen Trennzeichens (ein Komma, das von einer beliebigen Anzahl von Leerzeichen umgeben ist) aufteilen und zum Akkumulieren verwenden. Ich stellte cnt statt NR, weil die Anzahl der Datensätze NR verarbeitet verwenden, weiterhin kann größer sein als die tatsächliche Anzahl der relevanten Datensätze (cnt), wenn nicht alle Zeilen der Form sind INFO ... [...comma-separated-numbers...], die mit sed|awk seit sed garantiert nicht der Fall war, dass Alle Linien, die an awk weitergegeben wurden, waren relevant.
+0

Super! Danke auch für die Erläuterungen! –

0

Verwenden nawk oder /usr/xpg4/bin/awk auf Solaris.

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

Verwenden 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 
Verwandte Themen