これは次のように実行できます:
$ sed -e '
/BEGIN/,/END/!d
H;/BEGIN/h;/END/!d;g
' inp
それがどのように機能するかは、行の開始/終了範囲に対して、それらをホールドスペースに保存することです。その後、END 行に達するまで削除します。その時点で、何が保持されているかを思い出します。 OTW、何も出力されません.HTH.
cat input |
sed '/\*\*\*\*\* BEGIN \*\*\*\*\*/,/\*\*\*\*\* END *\*\*\*\*/ p;d' |
tac |
sed '/\*\*\*\*\* END \*\*\*\*\*/,/\*\*\*\*\* BEGIN *\*\*\*\*/ p;d' |
tac
tac
を持つことで機能します sed
になるように行を反転します 両方の順序で両方の区切り文字を見つけることができます。
pcregrep
で :
pcregrep -M '(?s)BEGIN.*?END'
これは、BEGIN と END が同じ行にある場合にも機能しますが、次のような場合には機能しません:
BEGIN 1 END foo BEGIN 2
END
どこで pcregrep
最初の BEGIN 1 END
をキャッチします 、しかし 2 番目のものではありません。
それらを処理するには、awk
を使用します 、次のことができます:
awk '
!inside {
if (match($0, /^.*BEGIN/)) {
inside = 1
remembered = substr($0, 1, RLENGTH)
$0 = substr($0, RLENGTH + 1)
} else next
}
{
if (match($0, /^.*END/)) {
print remembered $0
if (substr($0, RLENGTH+1) ~ /BEGIN/)
remembered = ""
else
inside = 0
} else
remembered = remembered $0 ORS
}'
次のような入力について:
a
BEGIN blah END BEGIN 1
2
END
b
BEGIN foo END
c
BEGIN
bar
END BEGIN
baz END
d
BEGIN
xxx
以下が得られます:
BEGIN blah END BEGIN 1
2
END
BEGIN foo END
BEGIN
bar
END BEGIN
baz END
どちらも、BEGIN から次の END までのすべてをメモリに格納する必要があります。そのため、最初の行に BEGIN が含まれているが END が含まれていない巨大なファイルがある場合、ファイル全体が無料でメモリに保存されます。
これを回避する唯一の方法は、ファイルを 2 回処理することですが、もちろん、入力が通常のファイル (たとえば、パイプではない) の場合にのみ実行できます。