これが私の要求です。
ログファイルをたどってgrepingしています。
各grep結果のコンテキストを取得したいと思います。
ただし、コンテキストはgrep -A/-B/-C
提供される行数の代わりに「パターンが一致するまで」でなければなりません。
たとえば、
これが私のログであるとします。
[l]
各ログ行のプレフィックスです。また、[logTypeA]
プレフィックスまたはプレフィックスもあります。[logTypeB]
[l][logTypeA] - Log line 1
[l][logTypeB] - Log line 2
[l][logTypeA] - Log line 3
....
Random data about Log line 3
....
[l][logTypeB] - Log line 4
今私のtail
コマンドがあれば、tail -f log_file.log | grep "[logTypeA]"
出力が表示されます。
[l][logTypeA] - Log line 1
[l][logTypeA] - Log line 3
ただし、grep結果のコンテキスト情報が必要であり、そのコンテキストはいくつかの行ではなく特定のパターンが一致するまで(この場合は[l])。
この例では、grepの結果を次のように作成したいと思います。
[l][logTypeA] - Log line 1
[l][logTypeA] - Log line 3
....
Random data about Log line 3
....
ここから(別の特定の一致まで、各grep一致の後に行を表示するには?sed
)、次のコマンドを試しました。tail
tail -f log_file.log | sed '/\[logTypeA\]/,/\[l\]/p'
しかし、これはうまくいかないようです。
どんなアイデアがありますか?
答え1
これはAwkで非常に一般的なパターンです。関連行を集めて「レコード」にし、すべてのレコードを収集し、特定の条件が満たされるとレコードを印刷します。
tail -f file |
awk '/\[l]/ { if (p && stored) print stored; stored = ""; p=0 }
/\[logTypeA]/ { p=1 }
{ stored = stored (stored ? ORS : "") $0 }
END { if (p) print stored }'
END
無限のストリームの場合、条件は実際には意味がありませんが、テストtail -f
中の最後のレコードを印刷する必要があるときに良い測定と厄介なテストの失敗を避けるために条件を含めましたが、このEND
規定なしには含めませんでした。
答え2
おそらくこれを行うにはPerlステートメントを使用します。 sedでこれを行うことができますが、sedの「意図しないTuring完全性」部分に到達し始めたように感じます。
Perl 1行(perl -ne
これが本当のポイントです)
echo '[l] boring\nboring data\n[l] boring\n[l]interesting\ndata\ndata\n[l]boring' | perl -ne '
if (/\[l\].*interesting/ ) { print $_; $collect=1 ; }
elsif (/\[l\]/) {$collect=0 }
elsif ($collect) {print $_}'
ちなみに、以下は同じことをする1行のsedコードです。 (使用されたsedの機能:第二コンバージョンを達成するには、時間条件付き実行を実装するため)。
echo '[l] boring\nboring data\n[l] boring\n[l\]interesting\ndata\ndata\n[l]boring' | sed -nE '/\[l\].*interesting/ {
p;
s/.*/collect/ ; x ; # store collect marker in the pattern space
b; # terminate processing
}
/\[l\]/ {
s/.*// ; x; # clear hold flag
b
}
/./ {
x;
s/collect/collect/;
T; x; p # print if we are collecting
}
'