複数行の開始タグと終了タグを使用してパターン別にテキストを取得する[重複]

複数行の開始タグと終了タグを使用してパターン別にテキストを取得する[重複]

欲求不満な方法で開始タグと終了タグを含むパターンを持つファイルから複数行を取得したいと思います。

たとえば、次のような入力があります。

ファイル.txt

START
test1
test2
foo
END
some
more text

START
test3
bar
test4
test5
END
even more

START
baz
test6
END

今私は探したいバー間のすべての内容を印刷します。スタートそして終わりだから私は次のようになります:

START
test3
bar
test4
test5
END

これまで私が持っているのは、次のgrepコマンドです。

grep -Pzo '(?s)START.*?bar.*?END' file.txt

問題は、この式が貪欲であり、次のように印刷されることです。

START      # starts at first "START"-tag, not the next one
test1      #
test2      #
foo        #
END        #
some       #
more text  #

START
test3
bar
test4
test5
END

grepフラグはまだ完了していません。--コンテキスト前/--コンテキスト後、前と後の行数が異なる可能性があるためです。

テキスト処理に使用されるツールは重要ではありません。通常のRedHatシステムで実行する必要があります。また、ツールが線をつかむ速度が速いほど良いです。約150MBの大容量ログファイルがあるためです。

誰かが私の目標を最もよく達成する方法を教えてもらえますか?


修正する:

はい、わかりました。don_crissti■リンクからコマンドを作成する方法を考えるだけです。解決策は次のとおりです。

ed -s file.txt <<< $'g/bar/?START?,/END/p\nq\n'

速い助けてくれてありがとう!

うん、結局繰り返しだった…

答え1

私の考えでは、あなたの問題は、貪欲ではないマッチがあなたが望むよりも多く食べることができるということです。終わりスタートS.これはうまくいくようです:

grep -Pzo '(?s)START(?:(?!END).)*?bar(?:(?!START).)*?END' file.txt

例のすべてのケースをカバーし、完了した場合>> file.txt

bar
START
test7
END

まだ有効です。

答え2

レコード区切り文字を指定できる場合は、awkを使用します。レコード区切り文字が「END」(1行に)の場合は、「bar」を含むレコードを探します。

awk 'BEGIN {RS = ORS = "\nEND\n"} /bar/' file.txt

STARTタグとENDタグの間に表示されるプロセステキスト。この変更はハッキングされているように感じますが、この場合は機能します。 END をレコード区切り文字として使用し、START キーワードの前のすべてのテキストを削除します。

awk '
    BEGIN {RS = ORS = "\nEND\n"} 
    {sub(/^.*\nSTART\n/, "START\n")} 
    /bar/
' file.txt

ENDの前に「START」が複数回表示されると、目的の結果が出ないことがあります。

foo
START
hello
START
bar
world
END
baz

次のように出力されます。

START
bar
world
END

答え3

perl -nE 'BEGIN {$/="\nEND\n"} say /(START.*test.*)/s'

@bobbelが指摘したように、空行区切り文字を避けるには、次のようsayに置き換えます。print

関連情報