私はstartStr
ケースとの間のすべてを得るために努力しています。私は使用方法とその間に発生するすべてのイベントを理解しています。発生事例を1つだけ制限する方法がわかりません。endStr
bbb
startStr
endStr
sed
bbb
入力例:
fff
startStr
aaa
bbb
ccc
endStr
xxx
yyy
startStr
ddd
endStr
ddd
bbb
希望の出力:
startStr
aaa
bbb
ccc
endStr
これが私が持っているものです:
$ sed -n -e '/startStr/,/endStr/ p' sample.txt
startStr
aaa
bbb
ccc
endStr
startStr
ddd
endStr
答え1
最初のstartStr
...については、endStr
次が含ま/bbb/
れます。
sed -n '/startStr/ {:n; N; /endStr/ {/\n[^\n]*bbb[^\n]*\n/ {p; q}; b}; bn}'
または
sed -n '/startStr/ {:n; N; /endStr/ {/\nbbb\n/ {p; q}; b}; bn}'
正規表現でない場合は、bbb
正確に必要な文字列です(最初からから\n
)。
説明する
住所の場合/startStr/
:
:n
ラベル設定- 次の行を読む
N
。 - 一致していることを確認してください
/endStr/
。- これが本当なら、
/\nbbb\n/
私たちが読んだこのブロックで発生を確認してください。- ある場合は、
{p; q}
「印刷と終了」を実行します。 - それ以外の場合は、
b
「このブロックをスローして次のブロックの検索を開始します」を実行します。
- ある場合は、
- これが本当なら、
- ブロックの終わりでない場合に移動します
:n
。つまり、読み続けます。
答え2
pcregrep
この仕事に関する私のアドバイスは次のとおりです。
pcregrep -M 'startStr(.|\n)*?bbb(.|\n)*?endStr' sample.txt
オプションを使用すると、貪欲な演算子なしで-M
複数行のパターンを一致させることができます。*?
残りは明確でなければなりません。
答え3
以前に一致したブロックがstartStr...endStr
ないブロックを含むように入力サンプルを変更します。bbb
$ cat ip.txt
startStr
foo
bar
endStr
fff
baz
startStr
aaa
bbb
ccc
endStr
xxx
yyy
startStr
ddd
endStr
ddd
bbb
awk
解決策
awk '/startStr/{f=1; m=0; buf = $0; next}
/bbb/ && f{m=1}
f{buf = buf ORS $0}
/endStr/ && f{f=0; if(m==1)print buf}
' ip.txt
/startStr/{f=1; m=0; buf = $0; next}
ブロックの開始を示すフラグの設定、一致のクリア、バッファの初期化、次の行に移動/bbb/ && f{m=1}
行にが含まれている場合は一致を設定しますbbb
。外部f
一致を防ぐために使用されます。bbb
startStr...endStr
f{buf = buf ORS $0}
フラグが設定されるたびに入力行を累積します。/endStr/ && f{f=0; if(m==1)print buf}
ブロックの最後に一致するものが見つかった場合は、バッファを印刷します。
一行で:
$ awk '/startStr/{f=1; m=0; buf = $0; next} /bbb/ && f{m=1} f{buf = buf ORS $0} /endStr/ && f{f=0; if(m==1)print buf}' ip.txt
startStr
aaa
bbb
ccc
endStr
入力ファイル全体を吸収することでより簡単なperl
解決策 - 同様のブロックがないと仮定しますstartStr...startStr...endStr
(例:first startStrなしendStr)
$ perl -0777 -ne '(@m) = /startStr.*?endStr\n/gs; print grep { /bbb/ } @m' ip.txt
startStr
aaa
bbb
ccc
endStr
答え4
sed -n -e '/startStr/,/bbb/p;/bbb/,/endStr/p' /path/to/input