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
$A
und / oder$B
. Je größer Sie diese Zahlen machen, desto langsamer wird es - aber Sie können sie einigermaßen groß machen.Sie können
gnu grep
mit-A
und-B
genau die Teile der Datei drucken, die Sie ausschließen möchten. Fügen Sie jedoch den-n
Schalter hinzu, um auch die Zeilennummern zu drucken. Formatieren Sie dann die Ausgabe und übergeben Sie sie als Befehlsskriptsed
, um diese Zeilen zu löschen:Dies sollte auch mit Dateien von Mustern funktionieren, an die
grep
über-f
Folgendes übergeben wird:Ich denke, dies könnte leicht optimiert werden, wenn drei oder mehr aufeinanderfolgende Zeilennummern in Bereiche zusammengefasst würden, um z. B.
2,6d
statt2d;3d;4d;5d;6d
... zu haben. Wenn die Eingabe nur wenige Übereinstimmungen aufweist, lohnt es sich nicht, dies zu tun.Andere Methoden, die die Zeilenreihenfolge nicht beibehalten und wahrscheinlich langsamer sind:
mit
comm
:comm
erfordert eine sortierte Eingabe, was bedeutet, dass die Zeilenreihenfolge in der endgültigen Ausgabe nicht beibehalten wird (es sei denn, Ihre Datei ist bereits sortiert). Sienl
wird verwendet, um die Zeilen vor dem Sortieren zu nummerieren,comm -13
druckt nur die für 2nd FILE eindeutigen Zeilen undcut
entfernt dann den von hinzugefügten Teilnl
(dh das erste Feld und das Trennzeichen:
)mit
join
:quelle
comm
schneller zu sein als das Original mitsed
undgrep
?Wenn es Ihnen nichts ausmacht
vim
:-Nes
Schaltet den nicht kompatiblen, stillen Ex-Modus ein. Nützlich für die Skripterstellung.+{command}
Sagen Sie vim, er soll{command}
in der Datei ausgeführt werden.g/${PAT}/
- In allen übereinstimmenden Zeilen/fff/
. Dies wird schwierig, wenn das Muster Sonderzeichen mit regulären Ausdrücken enthält, die Sie nicht so behandeln wollten..-${B}
- von 1 Zeile darüber.+${A}
- bis 2 Zeilen darunter (siehe:he cmdline-ranges
für diese beiden)d
- Löschen Sie die Zeilen.+w !tee
Schreibt dann auf die Standardausgabe.+q!
wird beendet, ohne die Änderungen zu speichern.Sie können die Variablen überspringen und das Muster und die Zahlen direkt verwenden. Ich habe sie nur aus Gründen der Klarheit verwendet.
quelle
Wie wäre es (mit GNU
grep
undbash
):Hier finden wir die zu
grep -B2 -A1 'fff' file.txt
verwerfenden Zeilen und verwenden diese als Eingabedatei, um die gewünschten Zeilen zu finden, die diese verwerfen.quelle
kos
die (jetzt gelöschte) Lösung, als ob doppelte Zeilen in der Eingabedatei vorhanden wären und einige außerhalb des Bereichs und andere innerhalb dieses Bereichs liegen. Dadurch werden alle gelöscht. Bei mehreren Vorkommen eines Musters werden Linien wie--
in der Eingabedatei (außerhalb der Bereiche) gelöscht, da das Trennzeichen--
ingrep
der Ausgabe angezeigt wird , wenn mehr als eine Linie mit dem Muster übereinstimmt (letzteres ist höchst unwahrscheinlich, aber wertvoll) Erwähnung, denke ich).Sie können ein ausreichend gutes Ergebnis erzielen, indem Sie temporäre Dateien verwenden:
Das Ergebnis ist gut genug, da Sie dabei Einrückungen verlieren können. Wenn es sich jedoch um eine XML- oder einrückungsunempfindliche Datei handelt, sollte dies kein Problem sein. Da dieses Skript ein RAM-Laufwerk verwendet, ist das Schreiben und Lesen dieser temporären Dateien genauso schnell wie das Arbeiten im Arbeitsspeicher.
quelle
Wenn Sie nur einige Zeilen vor einem bestimmten Marker ausschließen möchten, können Sie Folgendes verwenden:
(Glenn Jackman unter https://stackoverflow.com/a/1492538 )
Durch die Weiterleitung einiger Befehle können Sie das Vorher / Nachher-Verhalten erhalten:
quelle
awk
eine umgekehrte Datei, um folgende Zeilen zu behandeln, wenn Sie vorhaben, Zeilen zu beeinflussen, und kehren Sie das Ergebnis erneut um.Eine Möglichkeit, dies zu erreichen, besteht möglicherweise darin, eine Variable zu erstellen und Folgendes zu tun:
Auf diese Weise haben Sie immer noch Ihre Struktur. Und Sie können leicht von dem einen Liner sehen, was Sie entfernen möchten.
quelle
Wenn es nur 1 Treffer gibt:
Ansonsten (awk):
quelle