it-swarm.com.de

Entfernen Sie die Linie mit der Musterübereinstimmung und der nächsten Linie

Ich versuche, alle Instanzen einer Musterübereinstimmung aus einer Datei zu entfernen, wenn sie mit einem Muster übereinstimmt. Wenn es eine Übereinstimmung gibt, werden die (vollständige) Zeile mit dem übereinstimmenden Muster und die nächste Zeile entfernt.

Die nächste Zeile wird immer nach der Zeile mit der Musterübereinstimmung angezeigt, aber zusätzlich in anderen Bereichen der Datei.

Ich verwende grep und es löscht erwartungsgemäß alle Vorkommen der nächsten Zeile in der Datei.

Gibt es eine Möglichkeit, diese nächste Zeile genau dann zu entfernen, wenn sie nach der Zeile mit der Musterübereinstimmung liegt?

23
kenuse

Sie können sed mit den Befehlen N und d und einem {} block :

sed -e '/pattern here/ { N; d; }'

Für jede Zeile, die mit pattern here Übereinstimmt, wird der Code in {} Ausgeführt. N nimmt die nächste Zeile ebenfalls in den Musterbereich auf, und dann löscht d das Ganze, bevor mit der nächsten Zeile fortgefahren wird. Dies funktioniert in jedem POSIX-kompatiblen sed.

25
Michael Homer

Eine awk Lösung:

awk '/pattern/    { matched=1; next }
     1 == matched { matched = 0; next }
                  { print }' input-file

Zeile 1 sucht nach Linien, die dem Muster entsprechen, setzt ein Flag und überspringt die Linie. Zeile 2 überspringt eine Zeile, wenn das Flag gesetzt ist, setzt jedoch das Flag zurück. Zeile 3 druckt Zeilen, die nicht von einer der beiden anderen Zeilen übersprungen wurden.

Sie können dies in eine Zeile eingeben, wenn Sie möchten:

awk '/pattern/{matched=1;next} 1==matched{matched=0;next} {print}' input-file

Hier ist eine Variante, mit der Sie steuern können, wie viele Zeilen übersprungen werden sollen:

awk '/pattern/{skip=3;next} skip>0{--skip;next} {print}' input-file

Setzen Sie skip auf die Anzahl der Zeilen, die übersprungen werden sollen (zusätzlich zur übereinstimmenden Zeile).

5
Kenster

Die meisten seds drucken nicht die letzte Zeile, wenn Sie N auf $. Aber GNU sed wird. Wenn sich also das zu löschende Muster in der letzten Zeile befindet und Sie N drucken, ist es manchmal besser, das zu behalten Puffer voll - wie in, immer 2 Zeilen außer in den Zeilen, die Sie nicht drucken möchten. Sie könnten dies wie folgt tun:

seq 10 | sed -n 'x;/7/!g;//!p'

Das ist ein Beispiel mit seq als Eingabe. In jeder Zeile wird der Haltebereich und der Musterbereich vertauscht. Wenn die zuletzt gehaltene Zeile nicht mit einem 7(in diesem Fall) übereinstimmt, wird der Haltebereich mit der aktuellen Zeile überschrieben. Anschließend wird erneut überprüft, ob die gerade eingezogene Zeile - die aktuelle Zeile - ebenfalls nicht mit 7 Übereinstimmt, da sie sonst nicht gedruckt wird. In jeder Zeile werden also die vorherige und die aktuelle Zeile überprüft.

1
2
3
4
5
6
9
10

Und wenn Ihr Muster in die letzte Zeile fällt:

seq 10 | sed -n 'x;/10/!g;//!p' 

1
2
3
4
5
6
7
8
9

Ein weiteres Beispiel, um hoffentlich klarer zu demonstrieren, was gedruckt wird und was nicht:

sed -n 'x;/match/!g;//!p
' <<\DATA
    match 
    match 
    1not 
    2not 
    3not 
    4not 
    5not 
    match 
    6not 
    match                                                              
DATA

AUSGABE

2not
3not
4not
5not
5
mikeserv
cat sample
Pattern line
next after pattern line
this is another
random line
next after pattern line
has occured without.
now we have
another 
Pattern line
next after pattern line
let us see the output.

Jetzt gebe ich den folgenden Befehl aus.

sed -e '/Pattern \line/,+1d' sample

Dies ist die Ausgabe, die ich bekomme.

this is another
random line
next after pattern line
has occured without.
now we have
another 
let us see the output.

als nächstes nach der Musterzeile wird nicht entfernt, wenn es als separate Zeile nicht neben dem Muster auftritt.

Gemäß Michaels Kommentaren lautet die obige Syntax GNU. Sie können Folgendes ausprobieren:

sed -e '/Pattern \line/{N;d}' sample
4
Ramesh

Wie wäre es mit

sed '/pattern/ {$!N;d;}' file
4
steeldriver