grep 正規表現パターンは各行に一致し、すべての一致のみが表示され、同じ行に出力されます。

grep 正規表現パターンは各行に一致し、すべての一致のみが表示され、同じ行に出力されます。

ログ ファイルから行ごとにいくつかのパターンを抽出しようとしています。最初のタイムスタンプと、他の 2 つまたは 3 つの一致を抽出しようとしていますが、すべての一致が出現する行からのみ一致を印刷できるようにしたいと考えています。これを実行できる単一の grep コマンドはありますか、それとも各行をループする必要がありますか?

私のログラインはこんな感じです

2018-08-07 08:55:20 ERROR[t-dispatcher-24] - Error while processing message: code:[RequestTimeout], message:[{"from_addr_type": null, "transport_name": "999_abc_999_2_1", "in_reply_to": null, "group": null, "timestamp": "2018-08-07 07:55:19.795748", "from_addr": "341231231234", "message_type": "user_message", "helper_metadata": {}, "to_addr": "ABCD", "to_addr_type": null, "session_id": "157692", "content": "0013091779", "routing_metadata": {}, "message_version": "20110921", "transport_type": "XXXX", "provider": "abc_somewhere", "transport_metadata": {"abc_somewhere_XXXX": {"clientId": "XXXX157692", "starCode": "999", "session_id": "157692", "phase": "2", "dcs": "15", "requestId": "157692"}}, "session_event": "resume", "message_id": "5d9cab5353ff449783a737e8390a690b"}]

先頭のタイムスタンプ、"content" セクション、"to_addr" セクションなどの特定のグループを抽出できるようにしたいと考えています。

私はこれを思いつきました: grep -oP '(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})|"to_addr":"\K(\d+)|"content":\K"(.+?)"' | tr -d '\n'

しかし、3 つのパターンがすべて一致する行だけを選択することはできません。何が間違っているのでしょうか? 期待しすぎでしょうか?

答え1

|パターン間でOR を使用していますが、AND が必要です。

あなたのパターンでは、 を検索しています"to_addr":"\K(\d+)が、あなたの例では の値はto_addrなのでABCDとは一致せず、と \d+の間にはスペースがあります。についても同様です。"to_addr:"ABCD"content

to_addrが常に前である場合content:

grep -P '^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}.*?"to_addr": "\d+.*?"content": ".+?"' 

それ以外の場合は先読みを使用します:

grep -P '^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}(?=.*?"to_addr": "\d+)(?=.*?"content": "(.+?)")' 

一致したものだけを印刷したい場合は、Perl のワンライナーをお勧めします。

perl -ane 'print "$1\t$2\t$3\n" if (/^(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})(?=.*?"to_addr": "(\d+))(?=.*?"content": "(.+?)")/)' file

関連情報