Frage

Ich habe ein, das wie folgt aussieht:

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 Durchschnitt der 2. und 3. Felder in Klammern (840 und 0 im letzten Beispiel) berechnet. Eine noch härtere Frage: ist es möglich, nur den Durchschnitt des dritten Feldes zu erhalten, wenn die letzten nicht 0

Ich weiß, ich Ruby oder eine andere Sprache verwenden könnte ein Skript zu erstellen, aber ich möchte es in Bash zu tun. Gute Vorschläge auf Ressourcen oder Hinweise, wie erstellen ein solches Skript würde helfen.

War es hilfreich?

Lösung

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

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

Andere Tipps

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

Eine Beispielausgabe (für die Originaldaten):

  

avg2=2859.59, avg3=149.94

Natürlich können Sie nicht brauchen, um cat zu verwenden, wird es deswegen dort für die Lesbarkeit und die Tatsache zu verdeutlichen, dass Eingangsdaten von jedem Rohr kommen kann; wenn Sie direkt auf einer Datei, führen sed -ne '...' file | ... zu betreiben.


Bearbeiten

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 wieder. cat gelten.

Ein bisschen Erklärung:

  • sed druckt nur aus Linien (-n ... :p Kombination), die den regulären Ausdruck (Zeilen INFO enthalten, gefolgt durch eine beliebige Kombination von Ziffern, Leerstellen und Komma zwischen eckigen Klammern am Ende der Leitung, so dass für nachfolgende Leerzeichen und CR); wenn eine solche Linie übereinstimmt, nur halten, 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 Räumen (-F ' *, *') als Feldtrennzeichen; $1 entspricht der ersten Spalte (z.B. 8541), $2 an den zweiten Spalten usw. Fehlende zählen als Wert 0
    • am Ende, awk teilt die Akkumulatoren sum2 usw. durch die Anzahl der Datensätze verarbeitet, NR
  • gawk tut alles auf einen Schlag; es wird zunächst prüfen, ob jede Zeile im vorherigen Beispiel bestand den gleichen regulären Ausdruck sed (das außer im Gegensatz zu sed, awk erfordert keine \ in den runden Klammern fron Bereiche oder Interesse begrenzen). Wenn die Linie übereinstimmt, welche zwischen den runden Klammern ist endet in a [1], die wir dann den gleichen Separator aufgespalten unter Verwendung (ein Komma von einem beliebigen Anzahl von Räumen umgeben ist) und verwendet zu akkumulieren. Ich stellte cnt anstatt weiterhin NR zu verwenden, da die Anzahl der Datensätze verarbeitet NR größer sein kann als die tatsächliche Anzahl der relevanten Datensätze (cnt), wenn nicht alle Zeilen der Form INFO ... [...comma-separated-numbers...] sind, was nicht der Fall mit sed|awk war seit sed garantiert, dass alle auf awk bestanden Linien waren relevant.

Mit 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

Mit 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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top