Löschen eines Teils einer Textdatei und folgender Zeilen mit sed

8

Ich muss eine Datei wie folgt bearbeiten:

auto wlx00
allow-hotplug wlx00
iface wlx000 inet dhcp
iface wlx000 inet6 auto
  post-up sysctl -w net.ipv6.conf.wlx000.accept_ra=2
auto wlx000

Das Ziel ist es, die Zeilen zu löschen, die mit 'iface ... inet6' beginnen, und auch die nächsten Zeilen zu löschen, die mit Leerzeichen beginnen (kann keine oder mehr als eine sein):

iface wlx000 inet6 auto
  post-up sysctl -w net.ipv6.conf.wlx000.accept_ra=2

und halten Sie den Rest für das folgende Ergebnis intakt:

auto wlx00
allow-hotplug wlx00
iface wlx000 inet dhcp
auto wlx000

Ich habe es mit sed wie folgt versucht:

sed -i.old -r -e "/iface\s*\w*\s*inet6.*/,\${d;/^\s.*/d;}" /etc/configfile

aber es entfernt alles, was an der richtigen Stelle beginnt, aber bis zum Ende gelöscht wird. Ich möchte nur Zeilen entfernen, die nach dem ausgewählten iface-Text mit Leerzeichen versehen sind.

fcm
quelle
1
@fcm Bitte teilen Sie uns mit, ob die folgenden Lösungen in Ordnung sind. Wenn nicht, können wir es für Sie optimieren
1
@TNT nicht die gleiche Frage. Dies dient NICHT zum Löschen einer einzelnen Zeile, sondern zum Löschen einer Zeile sowie der folgenden Zeilen, die mit Leerzeichen versehen sind.
fcm
2
Theoretisch ein Duplikat, aber nicht in der Praxis - ich denke, es wäre gut, hier eine separate Antwort zu geben, die zeigt, wie man von einem bestimmten Muster durch nachfolgende Zeilen mit führenden Leerzeichen passt.
Jeff Schaller
1
@rudic lieferte eine ausgezeichnete und ausgearbeitete Antwort, die weit davon entfernt ist, einfach zu suchen und zu löschen. Nichts auf dem vorgeschlagenen Dup kommt dem nahe.
fcm

Antworten:

7

Probieren Sie diese Anpassung Ihres sedEinzeilers aus:

sed  '/iface\s*\w*\s*inet6.*/,/^[^ ]/ {/^[^ i]/!d}' file

Es entspricht dem Bereich von Ihrem ersten Muster bis zur ersten Zeile, die NICHT mit einem Leerzeichen beginnt, und löscht die Zeilen, die mit einem Leerzeichen oder einem "i" beginnen (für das führende iface). Umdenken muss, sollte das inach dem Block erforderlich sein.

Sieht so aus:

sed -n '/iface\s*\w*\s*inet6.*/ {:L; n; /^[ ]/bL;}; p' file

Bitte versuchen Sie es und melden Sie sich zurück.

RudiC
quelle
6

Ein Skript für Standard sed, das eine explizite Schleife verwendet, um die Zeilen zu löschen:

/^iface .* inet6/ {
    :again
    N
    s/.*\n//
    /^[[:blank:]]/b again
}

Das Skript findet die inet6Zeilen und hängt dann die nächste Zeile intern im Musterbereich an diese Zeile an (mit einem eingebetteten Zeilenumbruchzeichen dazwischen). Anschließend wird der Musterbereich bis einschließlich des ersten Zeilenumbruchzeichens gelöscht (dies löscht die ursprüngliche inet6Zeile). Dies wird so lange fortgesetzt, bis der Musterbereich nicht mehr mit einem Leerzeichen (Leerzeichen oder Tabulator) beginnt.

Testen:

$ cat file
auto wlx00
allow-hotplug wlx00
iface wlx000 inet dhcp
iface wlx000 inet6 auto
  post-up sysctl -w net.ipv6.conf.wlx000.accept_ra=2
auto wlx000
$ sed -f script.sed <file
auto wlx00
allow-hotplug wlx00
iface wlx000 inet dhcp
auto wlx000

Testen auf künstlichen Daten:

$ cat file
something1
something2
iface have a inet6 here
   delete me
   me too
   same here
something3
something4
iface more something inet6
   be gone
   skip this
something5
$ sed -f script.sed <file
something1
something2
something3
something4
something5

Das Skript als "Einzeiler":

sed -e '/^iface .* inet6/ {' -e ':a' -e 'N;s/.*\n//;/^[[:blank:]]/ba' -e '}'
Kusalananda
quelle
3

Sie haben bereits gute Antworten für das sedTool, aber lassen Sie mich einen anderen, meiner Meinung nach viel einfacheren Ansatz vorschlagen, indem Sie Folgendes verwenden pcregrep:

pcregrep -Mv '^iface.*inet6(.|\n )*' file

Die Regex sollte selbsterklärend sein - wir suchen nach Mustern, beginnend mit der Zeile ^iface.*inet6und dann mit der Gruppe eines beliebigen Zeichens ODER einer neuen Zeile, gefolgt von einem einzelnen Leerzeichen, das null oder mehrmals wiederholt wird. Dann müssen wir nur noch anweisen pcregrep, die multi-lineare Übereinstimmung mit der -MOption zuzulassen und das Ganze umzudrehen -v(übereinstimmende Teile werden entfernt).

jimmij
quelle
Normalerweise bevorzuge ich die Verwendung pcregrep, viel intuitiver.
Rui F Ribeiro