我有多个条目描述了事件在一个非常大的日志文件中,比如说一个日志。我想做两件事事件日志文件中的条目:
- 计算每个此类条目出现的次数。(这不是强制性要求,但如果有的话就好了。)
- 将实际条目提取到单独的文件中并稍后研究它们。
典型的事件条目如下所示,并且它们之间会有其他文本。所以在下面的例子中有两个事件条目,第一个包含两个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