2009-03-04 21 views
1

我有一個看起來像這樣:如何通過日誌文件進行計算

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] 

我想創建計算第二平均和第3場在括號中的shell腳本(840和在最後一個例子中爲0)。一個更加棘手的問題:只有當最後一個不是0時纔有可能獲得第3場的平均值?

我知道我可以使用Ruby或其他語言來創建腳本,但我想在Bash中使用它。任何關於資源的好建議或者如何創建這樣的腳本的提示都會有所幫助。

+0

這將是微不足道的awk來做到這一點。這是否算作「在bash中」呢? – Eddie 2009-03-04 23:15:23

回答

1

發佈我粘貼到你在IM這裏也答覆,只是因爲它讓我嘗試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 
6

使用bashawk

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

樣本輸出(原始數據):

avg2=2859.59, avg3=149.94

當然,您不需要使用cat,它包含在其中以便易讀並且說明輸入數據可以來自任何管道的事實;如果您必須對現有文件進行操作,請直接運行sed -ne '...' file | ...


編輯

如果您有機會獲得gawk(GNU AWK),您可以消除sed的需求如下:

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

同言論回覆。 cat適用。

的解釋的位:

  • sed只打印出在末端匹配包含INFO及隨後的數字,空格和方括號之間逗號的任何組合的正則表達式(線即線(-n ... :p組合)該線,允許尾隨空格和CR); 8541, 931, 0, 0
:如果有這樣的行相匹配,只有打印,看起來像( :p
  • SED將輸出線之前保持的方括號之間有什麼(\1,對應於正則表達式\(...\)之間有什麼)
  • awk使用包圍0或更多空格的逗號(-F ' *, *')作爲字段分隔符; $1對應於第一列(例如8541),第二等的$2等缺少列在最後算是價值0
    • awk劃分蓄電池sum2等受處理的記錄數,NR
  • gawk做一切在一杆;它將首先測試每條線是否與前面示例中傳遞的相同正則表達式匹配sed(除了與sed不同,awk從圍繞括號劃分區域或興趣開始不需要\)。如果線條匹配,圓括號之間的內容以[1]結尾,然後我們使用相同的分隔符(逗號被任意數量的空格包圍)分割並使用它進行累加。我介紹cnt,而不是繼續使用NR由於處理NR記錄的數量可以比的相關記錄的實際數目(cnt)如果不是全部行的形式INFO ... [...comma-separated-numbers...],這是不是這種情況與sed|awk因爲sed保證的更大的所有傳遞到awk的行都是相關的。
+0

太棒了!感謝您的解釋! – 2009-03-05 00:20:52

0

使用NAWK在/ usr/XPG4 /斌/ AWKSolaris

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

使用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 
相關問題