
我有多個條目描述了事件在一個非常大的日誌檔案中,比如說一個日誌。我想做兩件事事件日誌檔案中的條目:
- 計算每個此類條目出現的次數。
- 將實際條目提取到單獨的文件中並稍後研究它們。
典型的事件條目如下所示,它們之間會有其他文字。所以在下面的例子中有兩個事件條目,第一個包含兩個DataChangeEntry
有效負載,第二個包含一個DataChangeEntry
有效負載。
Data control raising event :DataControl@263c015d[[
#### DataChangeEvent #### on [DataControl name=PatternMatch_LegendTimeAxis, binding=.dynamicRegion1. beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxisPageDef_beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxis_xml_ps_taskflowid.dynamicRegion58. beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxisPageDef_beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxis_xml_ps_taskflowid.QueryIterator]
Filter/Collection Id : 0
Collection Level : 0
Sequence Id : 616
ViewSetId : PatternMatch.LegendTimeAxis_V1_0_SN49
==== DataChangeEntry (#1)
ChangeType : UPDATE
KeyPath : [2014-06-26 06:15:00.0, 0]
AttributeNames : [DATAOBJECT_CREATED, COUNTX, QueryName]
AttributeValues : [2014-06-26 06:15:00.0, 11, StrAvgCallWaitTimeGreaterThanThreshold]
AttributeTypes : [java.sql.Timestamp, java.lang.Integer, java.lang.String, ]
==== DataChangeEntry (#2)
ChangeType : UPDATE
KeyPath : [2014-06-26 06:15:00.0, 0]
AttributeNames : [DATAOBJECT_CREATED, COUNTX, QueryName]
AttributeValues : [2014-06-26 06:15:00.0, 9, AverageCallWaitingTimeGreateThanThreshold]
AttributeTypes : [java.sql.Timestamp, java.lang.Integer, java.lang.String, ]
]]
someother non useful text
spanning multiple lines
Data control raising event :DataControl@263c015d[[
#### DataChangeEvent #### on [DataControl name=PatternMatch_LegendTimeAxis, binding=.dynamicRegion1. beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxisPageDef_beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxis_xml_ps_taskflowid.dynamicRegion58. beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxisPageDef_beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxis_xml_ps_taskflowid.QueryIterator]
Filter/Collection Id : 0
Collection Level : 0
Sequence Id : 616
ViewSetId : PatternMatch.LegendTimeAxis_V1_0_SN49
==== DataChangeEntry (#1)
ChangeType : UPDATE
KeyPath : [2014-06-26 06:15:00.0, 0]
AttributeNames : [DATAOBJECT_CREATED, COUNTX, QueryName]
AttributeValues : [2014-06-26 06:15:00.0, 11, StrAvgCallWaitTimeGreaterThanThreshold]
AttributeTypes : [java.sql.Timestamp, java.lang.Integer, java.lang.String, ]
]]
==== DataChangeEntry
請注意,事件條目中的行數 可以是可變的。它也可以完全不存在,這表明事件負載為空,並且是一個錯誤條件,並且肯定也希望捕獲這種情況。
由於在這種情況下,條目的輸出跨越多行,因此我使用普通的 grep 並沒有走得太遠。所以我正在尋求專家的建議。
附:
- 讓我更明確地說明我的要求。我想逐字捕獲上面顯示的整個文字區塊,並可選擇計算遇到的此類區塊的實例數量。計算實例數量的選項很好,但不是強制性要求。
- 如果問題的解決方案是使用 awk,我想保存 awk 檔案並重新使用它。因此,請同時提及執行腳本的步驟。我知道 regex 和 grep 但我不熟悉 sed 和/或 awk。
答案1
我希望這能做到。事件進入events
檔案。訊息會傳送到標準輸出。
將此檔案儲存到 myprogram.awk(例如):
#!/usr/bin/awk -f
BEGIN {
s=0; ### state. Active when parsing inside an event
nevent=0; ### Current event number
printf "" > "events"
}
# Start of event
/^ *Data control raising event/ {
s=1;
dentries=0;
print "*** Event number: " nevent >> "events"
nevent++
}
# Standard event line
s==1 {
print >> "events"
}
# DataChangeEntry line
/^ *==== DataChangeEntry/ {
dentries ++
}
# End of event
s==1 && /^ *\]\]/ {
s=0;
print "" >> "events"
if(dentries==0){
print "Warning: Event " nevent " has no Data Entries"
}
}
END {
print "Total event count: " nevent
}
您可以透過不同的方式調用它:
myprogram.awk inputfile.txt
awk -f myprogram.awk inputfile.txt
範例輸出:
Warning: Event 3 has no Data Entries
Total event count: 3
您可以在工作目錄中呼叫的檔案中一起檢查所有事件events
。
答案2
一個非常簡單的方法是
awk '{print > NR".entry"}END{print NR" entries"}' RS="]]" file
這將為每個條目建立一個單獨的文件,並將找到的條目數列印到標準輸出。
解釋
NR
是 中的目前行號awk
。RS="]]"
將記錄分隔符號(定義「行」的內容)設為]]
。這意味著每個條目將被視為一行awk
。{print > NR".entry"}
:這會將目前行(條目)列印到名為[LineNumber].entry
.因此,1.entry
將包含第一個、2.entry
第二個等等。END{print NR" entries"}
:處理完整個輸入檔後執行 END 區塊。因此,此時NR
將是處理的條目數。
您可以將其儲存為別名或將其放入腳本中,如下所示:
#!/usr/bin/env bash
awk '{print > NR".entry"}END{print NR" entries"}' RS="]]" "$1"
foo.sh
然後,您可以使用目標檔案作為參數來執行腳本(假設它被呼叫並且位於您的 $PATH 中):
foo.sh file
您也可以調整輸出檔名。例如,要呼叫文件,請[date].[entry number].[entry]
使用以下命令:
#!/usr/bin/env bash
date=$(date +%Y%m%d)
awk '{print > d"."NR".entry"}END{print NR" entries"}' RS="]]" d="$date" "$1"
上面假設您的日誌檔案僅包含“事件”條目。如果情況並非如此,並且您可以有其他行,並且應忽略這些行,請改用:
#!/usr/bin/env bash
date=$(date +%Y%m%d)
awk '{
if(/\[\[/){a=1; c++;}
if(/\]\]/){a=0; print > d"."c".entry"}
if(a==1){print >> d"."c".entry"}
}' d="$date" file
或者,作為一句話:
awk '{if(/\[\[/){a=1; c++;}if(/\]\]/){a=0; print > d"."c".entry"}if(a==1){print >> d"."c".entry"}}' d=$(date +%Y%m%d) file