In den meisten Fällen ist die Verwendung von Don's vielleicht besser, aber nur für den Fall, dass die Datei wirklich groß ist und Sie nicht sedmit einer so großen Skriptdatei umgehen können (was bei mehr als 5000 Skriptzeilen der Fall sein kann). . Hier ist es mit plain sed:
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
Dies ist ein Beispiel für ein sogenanntes Schiebefenster bei der Eingabe. Es funktioniert durch den Bau eines Look-Ahead- Puffer mit $B-count-Zeilen erstellt wird, bevor jemals versucht wird, etwas zu drucken.
Und eigentlich sollte ich wahrscheinlich meinen vorherigen Punkt klarstellen: Der primäre Leistungsbegrenzer sowohl für diese Lösung als auch für die Don's wird direkt mit dem Intervall zusammenhängen. Diese Lösung wird mit größeren Intervall langsam Größen , während Don mit größeren Intervall verlangsamt Frequenzen . Mit anderen Worten, auch wenn die Eingabedatei sehr groß ist und das tatsächliche Intervall immer noch sehr selten auftritt, ist seine Lösung wahrscheinlich der richtige Weg. Wenn die Intervallgröße jedoch relativ überschaubar ist und häufig auftritt, sollten Sie diese Lösung wählen.
Also hier ist der Workflow:
- Wenn
$matchim Musterbereich eine \newline vorangestellt ist, sedwird Djede \newline, die davor steht, rekursiv gelöscht .
- Ich räumte auf
$match vorher den Musterraum komplett freigelegt - aber um Überlappungen einfach zu handhaben, scheint es viel besser zu sein, einen Orientierungspunkt zu hinterlassen.
- Ich habe auch versucht
s/.*\n.*\($match\)/\1/, es auf einen Streich zu bringen und der Schleife auszuweichen, aber wenn $A/$Bgroß sind, dieD Streich erweist sich Elete-Schleife als erheblich schneller.
- Dann ziehen wir die
Next-Eingabezeile vor einem \newline-Begrenzer ein und versuchen erneut, a zu Dlöschen/\n.*$match/ weiteres Mal indem wir auf unseren zuletzt verwendeten regulären Ausdruck w / verweisen //.
- Wenn der Musterraum übereinstimmt
$match, kann dies nur mit erfolgen$match am $BAnfang der Zeile geschehen - alle vorhergehenden Zeilen wurden gelöscht.
- Also fangen wir an, eine Schleife zu machen
$A weiter.
- Jeder Lauf dieser Schleife werden wir versuchen,
s///für ubstitute &selbst den $Ath \newline Charakter in Musterraum und, falls erfolgreich,t est wird verzweigen uns - und unseren ganzen $After Puffer - aus dem Skript vollständig das Skript über von oben zu beginnen mit der nächsten Eingabezeile, falls vorhanden.
- Wenn das
test nicht erfolgreich ist, werden wir bzum :top-Label zurückkehren und für eine andere Eingabezeile zurückkehren - möglicherweise wird die Schleife erneut gestartet, wenn dies $matchwährend des Sammelns von $After auftritt.
- Wenn wir an einem bekommen
$matchFunktion Schleife, dann werden wir versuchen, pdie rucken $letzten Zeile , wenn diese es ist, und wenn !nicht versuchen, s///für ubstitute &sich der$B th \newline Charakter in Musterraum.
- Wir werden das auch
ttesten und wenn es erfolgreich ist, verzweigen wir zum :PRint-Label.
- Wenn nicht, verzweigen wir zurück zu
:top und erhalten eine weitere Eingabezeile, die an den Puffer angehängt wird.
- Wenn wir es machen
:PRINT wir PRINT dann Dzum ersten ÉLETE bis \nin Musterraum ewline und das Skript erneut ausführen von oben mit dem, was bleibt.
Und diesmal, wenn wir es tun würden A=2 B=2 match=5; seq 5 | sed...
Der Musterraum für die erste Iteration bei :Print würde wie folgt aussehen:
^1\n2\n3$
Und so sedsammelt sich sein $Bvorheriger Puffer. Und so wird sedgedruckt, um $B-count-Zeilen hinter der erfassten Eingabe auszugeben . Dies bedeutet , dass unser vorheriges Beispiel gegeben, sedwürde PRINT 1ausgeben, und dann Delete das und sende wie einen Musterraum an die Spitze des Skripts zurück die aussieht:
^2\n3$
... und oben im Skript wird die Next-Eingabezeile abgerufen und die nächste Iteration sieht so aus:
^2\n3\n4$
Wenn wir also das erste Vorkommen von 5in input finden, sieht der Musterraum tatsächlich so aus:
^3\n4\n5$
Dann Dstartet die elete-Schleife und wenn sie durch ist, sieht es so aus:
^5$
Und wenn die Next-Eingabezeile gezogen wird, sedtrifft EOF und wird beendet. Zu diesem Zeitpunkt wurden nur die PLinien 1 und 2 gedruckt.
Hier ist ein Beispiellauf:
A=8 B=7 match='[24689]0'
seq 100 |
sed -ne:t -e"/\n.*$match/D" \
-e'$!N;//D;/'"$match/{" \
-e"s/\n/&/$A;t" \
-e'$q;bt' -e\} \
-e's/\n/&/'"$B;tP" \
-e'$!bt' -e:P -e'P;D'
Das druckt:
1
2
3
4
5
6
7
8
9
10
11
12
29
30
31
32
49
50
51
52
69
70
71
72
99
100