Můžete to provést následovně:
$ sed -e '
/BEGIN/,/END/!d
H;/BEGIN/h;/END/!d;g
' inp
Funguje to tak, že pro počáteční/koncový rozsah řádků je ukládá do úložného prostoru. Poté maže, dokud nenarazíte na řádek END. V tomto okamžiku si připomeneme, co je v držení. OTW, nic nedostaneme. HTH.
cat input |
sed '/\*\*\*\*\* BEGIN \*\*\*\*\*/,/\*\*\*\*\* END *\*\*\*\*/ p;d' |
tac |
sed '/\*\*\*\*\* END \*\*\*\*\*/,/\*\*\*\*\* BEGIN *\*\*\*\*/ p;d' |
tac
Funguje to tak, že máte tac
otočit řádky tak, aby sed
můžete najít oba oddělovače v obou řádech.
S pcregrep
:
pcregrep -M '(?s)BEGIN.*?END'
To také funguje, pokud jsou BEGIN a END na stejném řádku, ale ne v případech jako:
BEGIN 1 END foo BEGIN 2
END
Kde pcregrep
zachytí první BEGIN 1 END
, ale ne ten druhý.
Chcete-li to zvládnout, pomocí awk
, můžete udělat:
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
}'
Na vstupu jako:
a
BEGIN blah END BEGIN 1
2
END
b
BEGIN foo END
c
BEGIN
bar
END BEGIN
baz END
d
BEGIN
xxx
To dává:
BEGIN blah END BEGIN 1
2
END
BEGIN foo END
BEGIN
bar
END BEGIN
baz END
Oba potřebují do paměti uložit vše od ZAČÁTKU po následující KONEC. Takže pokud máte velký soubor, jehož první řádek obsahuje BEGIN, ale bez KONCE, celý soubor bude uložen v paměti pro nic.
Jediný způsob, jak to obejít, by bylo zpracovat soubor dvakrát, ale to lze samozřejmě provést pouze tehdy, když je vstupem běžný soubor (ne například roura).