欲求不満な方法で開始タグと終了タグを含むパターンを持つファイルから複数行を取得したいと思います。
たとえば、次のような入力があります。
ファイル.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