オプション部分を含むテキストブロックをGrepする

オプション部分を含むテキストブロックをGrepする

複数のエントリがありますイベント非常に大きなログファイルでは、ログ私は2つのことをしたい。イベントログファイル内のエントリ:

  1. このような各エントリの出現回数を数えます。(これは必須要件ではありませんが、あれば便利です。)
  2. 実際のエントリを別のファイルに抽出し、後で調べます。

典型的なイベントエントリは次のようになります。イベントエントリの間には他のテキストが入ります。以下の例では、イベント最初のエントリには 2 つのDataChangeEntry ペイロードが含まれ、2 番目のエントリには 1 つの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="]]"レコード区切り文字 (「行」を定義するもの) を に設定します]]。つまり、各エントリは によって 1 行として扱われますawk
  • {print > NR".entry"}: これは、現在の行 (エントリ) を というファイルに出力します[LineNumber].entry。したがって、 に1.entryは 1 番目、2.entry2 番目などが含まれます。
  • 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 

関連情報