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 d
entfernt) wird an den H
alten Platz angehängt . Nicht übereinstimmende Zeilen bar
werden dann gelöscht. Bei übereinstimmenden Zeilen wird der Musterbereich geleert, x
mit dem Haltebereich geändert und die führende leere Zeile im Musterbereich entfernt.
Bei großen Eingaben und wenigen Vorkommen bar
sollte 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'
foo
und die letzte findenbar
und alles dazwischen drucken, wenn überhaupt. Bei einem Stream müssten Sie bis zum ersten lesenfoo
und alle nachfolgenden Zeilen im Speicher bis zum EOF puffern, wobei der Puffer jedes Mal geleert wird, wenn a angezeigtbar
wird. Dies kann bedeuten, dass der gesamte Stream im Speicher gepuffert wird.