Sie können dies wie folgt erreichen:
$ sed -e '
/BEGIN/,/END/!d
H;/BEGIN/h;/END/!d;g
' inp
Wie es funktioniert, speichert es den Anfangs-/Endbereich von Zeilen im Haltebereich. Dann löscht, bis Sie die END-Zeile treffen. An diesem Punkt erinnern wir uns an das, was in der Warteschleife ist. OTW, wir bekommen nichts raus.HTH.
cat input |
sed '/\*\*\*\*\* BEGIN \*\*\*\*\*/,/\*\*\*\*\* END *\*\*\*\*/ p;d' |
tac |
sed '/\*\*\*\*\* END \*\*\*\*\*/,/\*\*\*\*\* BEGIN *\*\*\*\*/ p;d' |
tac
Es funktioniert mit tac
Kehren Sie die Zeilen um, sodass sed
kann beide Trennzeichen in beiden Reihenfolgen finden.
Mit pcregrep
:
pcregrep -M '(?s)BEGIN.*?END'
Das funktioniert auch, wenn BEGIN und END in derselben Zeile stehen, aber nicht in Fällen wie:
BEGIN 1 END foo BEGIN 2
END
Wobei pcregrep
fängt die erste BEGIN 1 END
ab , aber nicht die zweite.
Um diese zu handhaben, mit awk
, könnten Sie Folgendes tun:
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
}'
Bei einer Eingabe wie:
a
BEGIN blah END BEGIN 1
2
END
b
BEGIN foo END
c
BEGIN
bar
END BEGIN
baz END
d
BEGIN
xxx
Es ergibt:
BEGIN blah END BEGIN 1
2
END
BEGIN foo END
BEGIN
bar
END BEGIN
baz END
Beide müssen alles vom BEGIN bis zum folgenden END im Speicher speichern. Wenn Sie also eine riesige Datei haben, deren erste Zeile BEGIN enthält, aber kein END, wird die ganze Datei umsonst im Speicher abgelegt.
Der einzige Weg, dies zu umgehen, wäre, die Datei zweimal zu verarbeiten, aber das geht natürlich nur, wenn die Eingabe eine normale Datei ist (nicht zum Beispiel eine Pipe).