[英]Counting lines in a file during particular timestamps in bash
我正在安排一個每分鍾運行一次的cron,每分鍾給出REJECT
字數。 我的文件被連續記錄並且為了避免冗余讀取,我在使用tail -n + lastTimeWC運行腳本時存儲了上次讀取的行。 但是我如何計算每分鍾REJECT的數量。 樣本輸入:
20170327-09:15:01.283619074 ResponseType:REJECT
20170327-09:15:01.287619074 ResponseType:REJECT
20170327-09:15:01.289619074 ResponseType:REJECT
20170327-09:15:01.290619074 ResponseType:REJECT
20170327-09:15:01.291619074 ResponseType:REJECT
20170327-09:15:01.295619074 ResponseType:REJECT
20170327-09:15:01.297619074 ResponseType:REJECT
20170327-09:16:02.283619074 ResponseType:REJECT
20170327-09:16:03.283619074 ResponseType:REJECT
20170327-09:17:02.283619074 ResponseType:REJECT
20170327-09:17:07.283619074 ResponseType:REJECT
預期產出:
9:15 REJECT 7
9:16 REJECT 2
9:17 REJECT 2
Update1 :(使用Ed Morton的回答)
#!/usr/bin/bash
while :
do
awk -F '[:-]' '{curr=$2":"$3} (prev!="") && (curr!=prev){print NR, prev, $NF, cnt; cnt=0} {cnt++; prev=curr}' $1
sleep 60
done
這個腳本在60秒后不斷給我輸出。 但它應該只添加新的時間戳添加到日志文件($!)
假設9:18被添加,然后它應該開始包括答案(不再是9:15到9:18)
不要打印最后一個計數,因為它可能不完整的時間戳,只需在此之前打印計數:
$ awk -F '[:-]' '{curr=$2":"$3} (prev!="") && (curr!=prev){print prev, cnt, $NF; cnt=0} {cnt++; prev=curr}' file
09:15 REJECT 7
09:16 REJECT 2
如果你真的想要打印最后一個,那么只需在END部分添加一個打印:
$ awk -F '[:-]' '{curr=$2":"$3} (prev!="") && (curr!=prev){print prev, $NF, cnt; cnt=0} {cnt++; prev=curr} END{print prev, $NF, cnt}' file
09:15 REJECT 7
09:16 REJECT 2
09:17 REJECT 2
但是我想你不得不放棄那可能部分的結果,那么重點是什么呢?
請注意,您不必將所有結果存儲在數組中,然后在END部分中打印它們,只需在每次時間戳更改時打印它們。 除了不必要地使用內存之外,將所有結果存儲在數組中然后使用in
在END部分中使用循環打印它們的解決方案將以隨機(實際哈希)順序打印輸出,而不是時間戳發生的順序。你的意見(除非有時候運氣不好)。
而不是存儲輸入文件的行數(當時間戳結果在腳本的調用中被分割時可能導致錯誤的結果並且使得無法使用logrotate
或類似的東西來截斷日志文件,因為它變得很長/太久),存儲最后一個時間戳分析並在當前迭代之后開始,例如用cron執行相當的操作:
while :
do
results=( $(awk -F '[:-]' -v last="$lastTimeStamp" '{curr=$2":"$3} curr<last{next} (prev!="") && (curr!=prev){print prev, $NF, cnt; cnt=0} {cnt++; prev=curr}' file) )
numResults="${#results[@]}"
if (( numResults > 0 ))
then
printf '%s\n' "${results[@]}"
(( lastIndex = numResults - 1 ))
lastResult="${results[$lastIndex]}"
lastTimeStamp="${lastResult%% *}"
fi
sleep 60
done
或者如果你想使用行號,那么你可以做tail
而不是使用wc -l
來獲取文件的長度(包括你沒有打印的當前時間戳可能不完整的結果),請awk打印行號與每個時間戳關聯的最后一行之后的行:
$ awk -F '[:-]' '{curr=$2":"$3} (prev!="") && (curr!=prev){print NR, prev, $NF, cnt; cnt=0} {cnt++; prev=curr}' file
8 09:15 REJECT 7
10 09:16 REJECT 2
並在打印結果之前將其剝離以保存最后一個值。 最后一個值是你要做的事情tail -n +<startLineNr> | awk '...'
tail -n +<startLineNr> | awk '...'
與下一次迭代。
順便說一句,你沒有在你的示例輸入中向我們展示這一點,但是如果你的日志文件包含不包含REJECT的行並且你想要忽略這些行,那么只需在awk腳本的開頭添加$NF!="REJECT"{next}
。
您可以在Awk
執行此操作,方法是將分鍾值作為索引進行散列並假設狀態不會每分鍾更改 ,如下所示,
awk -F'[-:]' '{unique[$2":"$3]++; uniqueValue[$2":"$3]=$NF; next}END{for (i in unique) print i,uniqueValue[i],unique[i]}' file
09:15 REJECT 7
09:16 REJECT 2
09:17 REJECT 2
包括REJECT過濾器,日期和流版本(內存中沒有數組,只有最后一個計數器和日期參考
awk -F '-|:..[.]|pe:' '$NF=="REJECT"{if(L==$1"-"$2)C++;else{print L" REJECT " C;C=1;L=$1"-"$2}}END{print L" REJECT " C}' YourLog
包括評論中提到的“不退縮相同信息”(只需在代碼中看到重讀的“最后知道時間”)
CFile=Counter.log
# just to insure there is a counter file (could be empty) for awk input
touch ${CFile}
awk -F '-|:..[.]|pe:' -v CF="${CFile}" '
FNR==NR {
if( CF == FILENAME) {L=$0;next}
}
# dont treat element before
# (so we include last know time that was maybe still logging at last cycle)
L > ( $1 "-" $2 ) { next }
$NF=="REJECT" {
if(L==$1"-"$2)C++
else {
print L" REJECT " C;C=1;L=$1"-"$2
}
}
END{
print L" REJECT " C
# write new counter info
print L > CF
}
' ${CFile} YourLog
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.