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 sed
mit 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
$match
im Musterbereich eine \n
ewline vorangestellt ist, sed
wird D
jede \n
ewline, 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/$B
groß sind, dieD
Streich erweist sich Elete-Schleife als erheblich schneller.
- Dann ziehen wir die
N
ext-Eingabezeile vor einem \n
ewline-Begrenzer ein und versuchen erneut, a zu D
lö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 $B
Anfang 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 $A
th \n
ewline Charakter in Musterraum und, falls erfolgreich,t
est wird verzweigen uns - und unseren ganzen $A
fter Puffer - aus dem Skript vollständig das Skript über von oben zu beginnen mit der nächsten Eingabezeile, falls vorhanden.
- Wenn das
t
est nicht erfolgreich ist, werden wir b
zum :t
op-Label zurückkehren und für eine andere Eingabezeile zurückkehren - möglicherweise wird die Schleife erneut gestartet, wenn dies $match
während des Sammelns von $A
fter auftritt.
- Wenn wir an einem bekommen
$match
Funktion Schleife, dann werden wir versuchen, p
die rucken $
letzten Zeile , wenn diese es ist, und wenn !
nicht versuchen, s///
für ubstitute &
sich der$B
th \n
ewline Charakter in Musterraum.
- Wir werden das auch
t
testen und wenn es erfolgreich ist, verzweigen wir zum :P
Rint-Label.
- Wenn nicht, verzweigen wir zurück zu
:t
op und erhalten eine weitere Eingabezeile, die an den Puffer angehängt wird.
- Wenn wir es machen
:P
RINT wir P
RINT dann D
zum ersten ÉLETE bis \n
in 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 :P
rint würde wie folgt aussehen:
^1\n2\n3$
Und so sed
sammelt sich sein $B
vorheriger Puffer. Und so wird sed
gedruckt, um $B
-count-Zeilen hinter der erfassten Eingabe auszugeben . Dies bedeutet , dass unser vorheriges Beispiel gegeben, sed
würde P
RINT 1
ausgeben, und dann D
elete das und sende wie einen Musterraum an die Spitze des Skripts zurück die aussieht:
^2\n3$
... und oben im Skript wird die N
ext-Eingabezeile abgerufen und die nächste Iteration sieht so aus:
^2\n3\n4$
Wenn wir also das erste Vorkommen von 5
in input finden, sieht der Musterraum tatsächlich so aus:
^3\n4\n5$
Dann D
startet die elete-Schleife und wenn sie durch ist, sieht es so aus:
^5$
Und wenn die N
ext-Eingabezeile gezogen wird, sed
trifft EOF und wird beendet. Zu diesem Zeitpunkt wurden nur die P
Linien 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