查找包含可选部分的文本块

查找包含可选部分的文本块

我有多个条目描述了事件在一个非常大的日志文件中,比如说一个日志。我想做两件事事件日志文件中的条目:

  1. 计算每个此类条目出现的次数。(这不是强制性要求,但如果有的话就好了。)
  2. 将实际条目提取到单独的文件中并稍后研究它们。

典型的事件条目如下所示,并且它们之间会有其他文本。所以在下面的例子中有两个事件条目,第一个包含两个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 并没有走得太远。所以我正在寻求专家的建议。

附:

  1. 让我更明确地说明我的要求。我想逐字捕获上面显示的整个文本块,并可选择计算遇到的此类块的实例数量。计算实例数量的选项很好,但不是强制性要求。
  2. 如果问题的解决方案是使用 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 

相关内容