ファイルから一連の行を削除する方法は?

ファイルから一連の行を削除する方法は?

ログファイルを解析して重要なメッセージが見つかった場合は、電子メールを送信するkshスクリプトを作成しています。一部のメッセージは情報提供用なので無視したいと思います。

ログファイルの形式は次のとおりです。

2018-01-24.08.24.35.875675    some text

    more text
    more text
    more text
    more text

2018-01-24.08.24.37.164538    some text

    more text
    more text
    INF9999W        <-- informational text
    more text

2018-01-24.08.24.46.8602545    some text

    more text
    more text
    more text

タイムスタンプはメッセージ区切り文字として扱われ、タイムスタンプはその後のメッセージに属します。 「メッセージテキスト」が表示されるたびにファイルを検索してから、ファイルからメッセージ全体を削除したいと思います(前のタイムスタンプから次のタイムスタンプの直前まで)。

次を使用してその行を削除できるように、前と次のタイムスタンプの行番号を簡単に確認するにはどうすればよいですか?

awk 'NR<'$preceding_ts' || NR >='$following_ts'

私のアプローチは、すべてのタイムスタンプ行をファイルに入れてから、「情報テキスト」行#の前後のタイムスタンプ行が見つかるまでファイルを繰り返すことでした。特に大容量ファイルを扱うときは、作業量が多いようです。より効率的な方法はありますか?

integer inf_line
integer last_ts_line
integer cur_ts
cp $error_log $copy_log
while true
do
   inf_line=$(grep -n "INF99999W" $copy_log | head -1 | cut -f1 -d":")
   if [[ $inf_line -eq 0 ]]
   then
      break
   fi     
   grep -n -E "^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]-" $copy_log | cut -f1 -d":" > $ts_lines
   last_ts_line=99999999
   cat $ts_lines | while read cur_ts
   do       
      if [[ $cur_ts -gt $inf_line && $last_ts_line -lt $inf_line ]]
      then
         awk 'NR<'$last_ts_line' || NR >='$cur_ts'' $copy_log > $temp_log
         cp $temp_log $copy_log
         last_ts_line=$cur_ts
         break
      fi
      last_ts_line=$cur_ts
   done
   if [[ $last_ts_line -lt $inf_line ]]
   then
      awk 'NR<'$last_ts_line'' $copy_log > $temp_log
      cp $temp_log $copy_log
   fi
done

ありがとうございます。

ベストアンサー1

現在のメッセージの行を保存して実装し、メッセージの終わりにマークがない場合は、保存されたINFバッチを印刷します。ここで、d現在のメッセージ(dはデータを表す)を保持する行は、保存されたp行を印刷するかどうかを示します。

awk -vinfo='INF99+' \
    '/^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]/ {
         if (p) printf "%s", d; d = $0 ORS; p=1; next } 
     $0 ~ info {p=0} 
     {d = d $0 ORS} 
     END {if (p) printf "%s", d}' < log 

ここの最初のルールはタイムスタンプ行と一致し、trueの場合は保存された行を印刷し、その行を保存してから1にp設定します。 2番目の規則は、対応するパターンがあるp行が表示されている場合は0にリセットされます。パターンが変数に設定されます。 3番目のルールは現在の行を収集された行に追加し、このルールは設定されている場合は収集された行のみを印刷します。pinfo-vinfo=...ENDp


infoタイムスタンプ行のパターンを確認するために、次のように作成することもできます。

awk -vinfo='INF99+' \
    '/^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]/ {
         if (p) { printf "%s", d }; d = ""; p=1; } 
     $0 ~ info {p=0} 
     {d = d $0 ORS} 
     END {if (p) printf "%s", d}' < log 

通常、awkPerlやPerlでこのような内容を書くのはおそらく良い考えです。結果は、少なくとも数十のforkなどgrepawkコピーを持つシェルスクリプトよりはるかに高速です。cut

おすすめ記事