「grep-zoP」ですべての一致を個別に表示するにはどうすればよいですか?
私はこのフォームにファイルを持っています:
X/this is the first match/blabla
X-this is
the second match-
and here we have some fluff.
そして、「X」の後と同じマーカーの間に表示されるすべてのものを抽出したいと思います。したがって、「X + match +」がある場合、「X」の後、マーカー「+」の間に表示されるため、「match」を取得したいと思います。
したがって、指定されたサンプルファイルについて、次の出力が必要です。
this is the first match
その後
this is
the second match
Xとそれに続くマーカーの間のすべてのコンテンツを、次を使用して取得することができました。
grep -zPo '(?<=X(.))(.|\n)+(?=\1)' file
あれは:
grep -Po '(?<=X(.))(.|\n)+(?=\1)'
X(something)
と一致し、その後にそれがキャプチャされ、最後にと一致します(ここでの回答(?=\1)
に基づいてコードを作成しました)。- 私
(.|\n)
は新しい行を含むすべてのものを照合するために使用し-z
、grepでも新しい行を照合するために使用することに注意してください。
したがって、これはうまく機能します。唯一の問題は、出力の表示にあります。
$ grep -zPo '(?<=X(.))(.|\n)+(?=\1)' file
this is the first matchthis is
the second match
ご覧のとおり、すべての一致が一緒に表示され、「これが最初の一致です」の後に「これが2番目の一致です」が続き、区切り文字はまったくありません。これは、すべてのファイルを改行(「mangrep」を引用)ではなくゼロバイト(ASCII NUL文字)で終了する一連の行として扱う「-z」の使用法に由来することを私は知っています。
だから:これらすべての結果を別々に取得する方法はありますか?
GNUAwkでも試しました。
awk 'match($0, /X(.)(\n|.*)\1/, a) {print a[1]}' file
しかし、うまくいきませんでした(\n|.*)
。
回答
一致を印刷するとすぐに、セパレータが正確にどこにあったかに関する情報が失われるため、ユースケースは一種の問題があります。しかし、それが許容できる場合は、に配管してみてくださいxargs -r0
。
grep -zPo '(?<=X(.))(.|\n)+(?=\1)' file | xargs -r0
これらのオプションはGNU拡張機能ですが、そうですgrep -z
(ほとんど)grep -P
ので、おそらくそれは許容できます。
awk
正規表現定義内の後方参照をサポートしていません。
回避策:
$ grep -zPo '(?s)(?<=X(.)).+(?=\1)' ip.txt | tr '\0' '\n' this is the first match this is the second match # with ripgrep, which supports multiline matching $ rg -NoUP '(?s)(?<=X(.)).+(?=\1)' ip.txt
this is the first match
this is
the second match
の(?s)X(.)\K.+(?=\1)
代わりに使用することもできます(?s)(?<=X(.)).+(?=\1)
。また、match+xyz+foobaz
入力との一致を避けるために、ここで貪欲でない数量詞を使用することもできますX+match+xyz+foobaz+
と perl
$ perl -0777 -nE 'say $& while(/X(.)\K.+(?=\1)/sg)' ip.txt
this is the first match
this is
the second match
これは、RS
とを利用した別のgnu-awkソリューションRT
です。
awk -v RS='X.' 'ch != "" && n=index($0, ch) { print substr($0, 1, n-1)
}
RT {
ch = substr(RT, 2, 1)
}' file
this is the first match
this is
the second match
複数文字のRS、RT、およびgensub()用のGNU awkを使用し、ファイル全体をメモリに読み込む必要はありません。
$ awk -v RS='X.' 'NR>1{print "<" gensub(end".*","",1) ">"} {end=substr(RT,2,1)}' file
<this is the first match>
<this is
the second match>
明らかに、各出力レコードの開始/終了を確認できるように、「<」と「>」を追加しました。
上記の文字の後にあることを前提とX
非繰り返し正規表現metachar(例えばないが.
、^
、[
、など)ので、メーリングリストへ
GNUgrep -z
は、入出力レコードをnull文字で終了します(などの他のツールと組み合わせて使用すると便利ですsort -z
)。pcregrepはそれを行いません:
pcregrep -Mo2 '(?s)X(.)(.+?)\1' file
-onumber
used instead of lookarounds. ?
lazy quantifier added (in case \1
occurs later).