ログファイルがあり、bashスクリプトを介してデータを「grep」しようとしています。私が特に興味を持っているデータは、「ERR-」パターンを持ち、読みやすくするために各項目の後に空白行を含む2つのタイムスタンプ(親タイムスタンプを含む)の間のすべての行です。
サンプルログファイル:
Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck
Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log
Tue May 24 21:47:25 2022
im some output
Tue May 24 21:47:25 2022
im some output too
im some output aswell
Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421
Tue May 24 21:49:07 2022
Completed process xyz
だから私が望む出力は次のようになります。
Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck
Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log
Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421
私は大きな成功なしにsed / awk / catの組み合わせを試しました。私が問題がある場所は次のとおりです。
- ERRには常にタイムスタンプの前に2行は含まれていません。
- タイムスタンプブロックには複数のERRがあります。
- 日付は明らかに変更されるため、フォーマットは変更されませんが、ハードコーディングしたくありません。
事前にありがとう
答え1
スクリプトtst.awk
:
function print_r() { if (e) print r; r = ""; e = 0 }
/^([[:alpha:]]{3} ){2}[[:digit:]]{1,2} [[:digit:]]{2}(:[[:digit:]]{2}){2} [[:digit:]]{4}$/ {
print_r()
}
/^ERR-/{ e = 1 }
{ r = r ORS $0 }
END{ print_r() }
使用法および出力:
$ awk -f tst.awk file
Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck
Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log
Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421
独自の式を使用してタイムスタンプまたはエラーを示すことができます。これは、提示された形式に一致する行全体です(日付検証なし)。行の先頭に「ERR-」を追加します。
メモ:
r
エラーが見つかった場合は、レコード()を印刷する関数()を定義しますe
。これら2つの変数も印刷後にリセットする必要があります。の場合、awk
値で初期化されていない変数は空の文字列またはゼロと評価されます。日付の正規表現が一致したときにこの関数を呼び出します。古いロギングを完了し、新しい履歴の保存を開始します。履歴は複数行のログなので、印刷する必要があるかどうかはまだわかりません。
エラーパターンが一致する場合を設定します
e
。各行ごとに既存のレコードに行を追加し、
ORS
出力レコード区切り文字(デフォルトの改行)で区切ります。また、出力行間の空白行はの先頭に配置されますr
。r
ここで新しいタイムスタンプを取得すると、常に空の文字列になります。END
最後のレコードがまだ残っているので、関数をもう一度呼び出します。
答え2
使用幸せ(以前のPerl_6)
~$ raku -e 'my @a=slurp; @a.=split(/ <?after ^^ ERR \V* > \n <?before ^^ Tue > /); \
put $_.subst(/^ <(.+)> ^^ Tue/) ~ "\n" if /^^ ERR / for @a;' file
ERR
問題は、行があるタイムスタンプレコードがあり、行がないレコードがあり、後者を削除したいようです。
上記のファイルは配列slurp
で構成されています。@a
次に、始まる@a
行で終わるレコードの間にsplit
ゼロ個以上の非垂直スペース文字が続き、次に始まる行の前にあります。\n
<?after ^^ ERR \V* >
ERR
\V
<?before ^^ Tue >
Tue
2番目のドアでは、outがput(…)
スタイリッシュです。これらの要素は、条項の専門家に@a
個別に(自動で)表示されます。各要素は条件付きでテストされ、 : で始まる行が含まれていることを確認します。したがって、要素が置き換えられ、前のすべての先行文字が削除されます。$_
for
if /^^ ERR/
ERR
if
$_
$_.subst(/^ <(.+)> ^^ Tue/)
内部Tue
本質的に、.subst
ここで置き換えがないことは、キャプチャタグ間の一致を削除することを意味します<(
。)>
個々のレコードを区別するために、要素$_.subst(…) ~ "\n"
は~
チルダとレコードを区切る改行文字に"\n"
リンクされています。
入力例:
Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck
Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log
Tue May 24 21:47:25 2022
im some output
Tue May 24 21:47:25 2022
im some output too
im some output aswell
Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421
Tue May 24 21:49:07 2022
Completed process xyz
出力例:
Tue May 24 21:22:12 2022
ERR-0045 Lock detected in /tmp/file.lck
Tue May 24 21:44:12 2022
Errors in file /tmp/filename01.trc:
ERR-0001: Error detected. /tmp/filename.log
Tue May 24 21:48:03 2022
Errors in file /tmp/filename09.trc:
ERR-0100: error
ERR-0050: failure of sorts.
ERR-0052: line 3421
もちろん上記は簡単な実装です(読みやすさを高めるためのものです)。別の曜日に始まる日付を処理するには、Tues
上記の内容を次のように置き換えます。
[ Mon || Tue || Wed || Thu || Fri || Sat || Sun ]
(具体性に問題がある場合は、正規表現に月を追加する方法を上記のコードで明確に確認できます。)