Hier ist ein anderer Weg mit sed:
sed '/foo/,$!d;H;/bar/!d;s/.*//;x;s/\n//' infile
Jede Zeile im /foo/,$Bereich (Zeilen, die !nicht in diesem Bereich liegen, wird dentfernt) wird an den Halten Platz angehängt . Nicht übereinstimmende Zeilen barwerden dann gelöscht. Bei übereinstimmenden Zeilen wird der Musterbereich geleert, xmit dem Haltebereich geändert und die führende leere Zeile im Musterbereich entfernt.
Bei großen Eingaben und wenigen Vorkommen barsollte dies (viel) schneller sein, als jede Zeile in den Musterraum zu ziehen und dann jedes Mal den Musterraum auf zu überprüfen bar.
Erklärt:
sed '/foo/,$!d # delete line if not in this range
H # append to hold space
/bar/!d # if it doesn't match bar, delete
s/.*// # otherwise empty pattern space and
x # exchange hold buffer w. pattern space then
s/\n// # remove the leading newline
' infile
Sicher, wenn dies eine Datei ist (und in den Speicher passt), können Sie einfach Folgendes ausführen:
ed -s infile<<'IN'
.t.
/foo/,?bar?p
q
IN
weil ed kann vorwärts und rückwärts suchen .
Sie können sogar eine Befehlsausgabe in den Textpuffer lesen, wenn Ihre Shell die Prozessersetzung unterstützt:
printf '%s\n' .t. /foo/,?bar?p q | ed -s <(your command)
oder wenn nicht, mit gnu ed:
printf '%s\n' .t. /foo/,?bar?p q | ed -s '!your command'
foound die letzte findenbarund alles dazwischen drucken, wenn überhaupt. Bei einem Stream müssten Sie bis zum ersten lesenfoound alle nachfolgenden Zeilen im Speicher bis zum EOF puffern, wobei der Puffer jedes Mal geleert wird, wenn a angezeigtbarwird. Dies kann bedeuten, dass der gesamte Stream im Speicher gepuffert wird.