Ich verwende diese
cat foo.txt | sed "/bar/d"
, um Zeilen zu entfernen, die die Zeichenfolge bar
in der Datei enthalten.
Ich möchte diese Zeilen und die Zeile jedoch direkt entfernen danach . Vorzugsweise in sed
, awk
oder einem anderen Tool, das in MinGW32 verfügbar ist.
Es ist eine Art Umkehrung von dem, was ich in grep
mit -A
und -B
erhalten kann, um auch übereinstimmende Zeilen zu drucken als Zeilen vor / nach der übereinstimmenden Zeile.
Gibt es eine einfache Möglichkeit, dies zu erreichen?
Kommentare
- Nur für Information: Ich ‚ analysiere Protokolle, in denen Einträge zweizeilig sind. Ich möchte also einen Eintrag finden, der zum Muster passt, und ihn sowie die nächste Zeile entfernen. Daher muss ich ‚ keine aufeinanderfolgenden Übereinstimmungszeilen verarbeiten, aber trotzdem danke für die Vollständigkeit Ihrer Antworten!
Answer
Wenn Sie GNU sed haben (also nicht eingebettetes Linux oder Cygwin):
sed "/bar/,+1 d"
Wenn Sie Wenn bar
in zwei aufeinander folgenden Zeilen vorhanden ist, wird die zweite Zeile gelöscht, ohne sie zu analysieren. Wenn Sie beispielsweise eine dreizeilige Datei bar
/ bar
/ foo
haben, Die Zeile foo
bleibt erhalten.
Kommentare
- +1 für die Länge 🙂 Insbesondere Beispiel Ich habe keine ‚ keine aufeinanderfolgenden
bar
s, so dass diese sehr einfach zu merken ist. -
sed '/bar/d'
, wenn Sie nur “ Zeile mit einer bestimmten Zeichenfolge entfernen möchten “ und nicht das nächste. - Wenn ich nach Mathe alle Zeilen entfernen möchte, dann?
- @Pandya Das ‚ ist anders. Sie können z.B.
sed '/math/q'
- @ A.K. Wenn Sie nur die übereinstimmende Zeile löschen möchten, ist ‚ noch einfacher:
sed '/bar/d'
Antwort
Wenn bar
in aufeinanderfolgenden Zeilen auftreten kann, können Sie Folgendes tun:
awk "/bar/{n=2}; n {n--; next}; 1" < infile > outfile
, das angepasst werden kann, um mehr als 2 Zeilen zu löschen, indem die 2 oben mit der Anzahl der zu löschenden Zeilen einschließlich der übereinstimmenden geändert werden.
Wenn nicht, ist dies der Fall „s einfach in sed
mit @ MichaelRollins“ -Lösung oder:
sed "/bar/,/^/d" < infile > outfile
Kommentare
- Das andere Plus in der AWK-Lösung ist, dass ich
/bar/
durch ersetzen kann/bar|baz|whatever/
. Insed
scheint diese Syntax ‚ nicht zu funktionieren. - @ jakub.g, ich habe GNU sed ( v4.4 jetzt). Ich bin mir nicht sicher über die anderen. Was ich weiß ist, dass es “ basic “ Syntax für reguläre Ausdrücke standardmäßig verwendet. Deshalb hat Ihr Beispiel nicht ‚ funktioniert nicht. Um das zu erreichen, was Sie wollen, können Sie entweder einen Backslash vor jede vertikale Linie setzen oder
sed
bitten, “ extended “ reguläre Ausdrücke. Weitere Informationen finden Sie hier: gnu.org/software/sed/manual/html_node/… . Bitte beachten Sie, dass dies auch fürgrep
gilt. Hier ist ‚ mein eigenes Arbeitsbeispiel:echo $'0a\n1b\n2c' | sed '/0a\|1b/d'
.
Antwort
Ich spreche nicht fließend sed, aber es ist einfach, dies in awk zu tun:
awk "/bar/{getline;next} 1" foo.txt
Die Das awk-Skript lautet: Für eine Zeile mit einem Balken rufen Sie die nächste Zeile (getline) ab und überspringen dann alle nachfolgenden Verarbeitungen (next). Das 1-Muster am Ende druckt die verbleibenden Zeilen.
Update
Wie im Kommentar ausgeführt, funktionierte die obige Lösung nicht mit aufeinanderfolgenden bar
. Hier ist eine überarbeitete Lösung, die dies berücksichtigt:
awk "/bar/ {while (/bar/ && getline>0) ; next} 1" foo.txt
Wir lesen jetzt weiter, um alle / bar / Zeilen zu überspringen.
Kommentare
- Um
grep -A
100% zu replizieren, müssen Sie auch eine beliebige Anzahl aufeinanderfolgender Zeilen korrekt (durch Entfernen des gesamten Blocks und 1 Zeile danach).
Antwort
Sie sollten die Skriptfunktionen von sed nutzen, um dies zu erreichen.
$ sed -e "/bar/ { $!N d }" sample1.txt
Beispieldaten:
$ cat sample1.txt foo bar biz baz buz
Mit dem Befehl „N“ wird die nächste Eingabezeile an den Musterbereich angehängt. In Kombination mit der Zeile aus der Musterübereinstimmung (/ bar /) werden die Zeilen gelöscht, die Sie löschen möchten. Sie können dies dann tun normal löschen mit dem Befehl „d“.
Kommentare
- Wie gebe ich eine neue Zeile in die Konsole ein? Oder ist dies nur ein Skript?
- @ jakub.g: mit GNU sed:
sed -e '/bar/{N;d}' sample1.txt
Antwort
Wenn eine Zeile unmittelbar nach einer Übereinstimmung entfernt werden soll, muss Ihr sed
-Programm aufeinanderfolgende Übereinstimmungen berücksichtigen. Mit anderen Worten, wenn Sie eine Zeile nach einer Übereinstimmung entfernen, die auch übereinstimmt, sollten Sie wahrscheinlich auch die Zeile entfernen, die darauf folgt.
Sie ist einfach genug implementiert – aber Sie müssen ein wenig zurückblicken
printf %s\\n 0 match 2 match match \ 5 6 match match match \ 10 11 12 match 14 15 | sed -ne"x;/match/!{g;//!p;}"
0 6 11 12 15
Dabei werden die Halte- und Musterbereiche für jede eingelesene Zeile vertauscht, sodass die letzte Zeile jedes Mal mit der aktuellen Zeile verglichen werden kann. Wenn also sed
eine Zeile liest, tauscht sie den Inhalt ihrer Puffer aus – und die vorherige Zeile ist dann der Inhalt ihres Bearbeitungspuffers, während die aktuelle Zeile in den Haltebereich gestellt wird.
Also sed
überprüft die vorherige Zeile auf Übereinstimmung mit match
und wenn Die !
hat die beiden Ausdrücke in der {
-Funktion }
nicht ausgeführt. sed
et den Haltebereich durch Überschreiben des Musterbereichs – was bedeutet, dass sich die aktuelle Zeile dann sowohl im Halte- als auch im Musterbereich befindet – und dann überprüft es//
, ob es mit seinem zuletzt kompilierten regulären Ausdruck übereinstimmt – match
– und Wenn es nicht match
ist, wirdp
gedruckt.
Dies bedeutet, dass eine Zeile nur gedruckt wird, wenn sie nicht match
und die unmittelbar vorhergehende Zeile nicht ist match
. Außerdem wird auf unnötige Auslagerungen für Sequenzen von match
es verzichtet.
Wenn Sie eine Version wünschen, die eine beliebige Anzahl von Zeilen löschen kann Wenn ein match
auftritt, ist etwas mehr Arbeit erforderlich:
printf %s\\n 1 2 3 4 match \ match match 8 \ 9 10 11 12 13 \ 14 match match \ 17 18 19 20 21 | sed -net -e"/match/{h;n;//h;//!H;G;s/\n/&/5;D;}" -ep
. ..ersetzen Sie die 5 durch die Anzahl der Zeilen (einschließlich der übereinstimmenden Zeile) , die Sie entfernen möchten …
1 2 3 4 12 13 14 21