尋找包含可選部分的文字區塊

尋找包含可選部分的文字區塊

我有多個條目描述了事件在一個非常大的日誌檔案中,比如說一個日誌。我想做兩件事事件日誌檔案中的條目:

  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 

相關內容