Wie ersetze ich einen mehrzeiligen Code durch sed?

9

Ich habe eine große Datei mit Sonderzeichen. Dort gibt es einen mehrzeiligen Code, den ich ersetzen möchte sed.

Dies:

  text = "\
    ------                                                           ------\n\n\
    This message was automatically generated by email software\n\
    The delivery of your message has not been affected.\n\n\
    ------                                                           ------\n\n"

Muss sich in Folgendes verwandeln:

text = ""

Ich habe den folgenden Code ausprobiert, aber kein Glück:

sed -i '/  text = "*/ {N; s/  text = .*affected.\./  text = ""/g}' /etc/exim.conf

Es ersetzt nichts und zeigt keine Fehlermeldungen an

Ich habe damit gespielt, aber alles, was ich versuche, funktioniert nicht.

Klinge19899
quelle
Muss es sein sedoder sind Sie offen für andere Tools? Kann es "innerhalb des text=Blocks sein? Kann es andere Fälle text = in Ihrer Datei geben? Wird es immer 4 Textzeilen geben oder kann es mehr / weniger geben?
Terdon
Vorzugsweise sedoder alles, was keine Installation auf einem CentOS-Server erfordert. Out of the Box Werkzeuge
Blade19899
@terdon Es gibt keine anderen text = im Ordner, das Ergebnis muss sein text = "". Die Dateien enthalten 891 Codezeilen. Also, es muss den anderen Text respektieren.
Blade19899
Möchten Sie die Datei überschreiben oder nur die Ausgabe ändern?
JoH1
@Moonstroke KEIN ÜBERSCHREIBEN. Es muss nur den Text ersetzen - wie in meiner Frage zu sehen - text = "". Wie in meiner Frage zu sehen.
Blade19899

Antworten:

15

Perl zur Rettung:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~ bearbeitet die Datei "an Ort und Stelle" und hinterlässt eine Sicherungskopie
  • -0777 liest die gesamte Datei auf einmal, nicht zeilenweise

Die Ersetzung s///funktioniert ähnlich wie in sed (dh sie stimmt überein, text = "gefolgt von etwas anderem als doppelten Anführungszeichen bis zu einem doppelten Anführungszeichen), aber in diesem Fall funktioniert sie für die gesamte Datei.

Choroba
quelle
5

Sie müssen den Musterraum überprüfen und die Next-Linie weiter ziehen, wenn sie nicht übereinstimmt, z

sed '/text = "/{              # if line matches text = "
:b                            # label b
$!N                           # pull in the next line (if not the last one)
/"$/!bb                       # if pattern space doesn't end with " go to label b
s/".*"/""/                    # else remove everything between the quotes
}' infile

mit gnu sedkannst du es schreiben als

sed '/text = "/{:b;$!N;/"$/!bb;s/".*"/""/}' infile

Das ist jedoch nicht sehr effizient. Wählen Sie besser den Bereich aus /text = "/,/"/, ändern Sie die erste Zeile und löschen Sie den Rest:

sed '/text = "/,/"/{            # in this range
/text = "/!d                    # delete all lines not matching text = "
s/\\/"/                         # replace the backslash with quotes (this is only
}' infile                       # executed if the previous d wasn't executed)

Auch hier können gnu sedSie es als Einzeiler schreiben:

sed '/text = "/,/"/{/text = "/!d;s/\\/"/}' infile
don_crissti
quelle
3

Persönlich würde ich dies in Perl tun. Wenn wir davon ausgehen können, dass es "vor dem Abschluss keine gibt ", können Sie Folgendes tun:

perl -0pe 's/(text\s*=\s*)".*?"/$1""/s' file

Der -0schlürft die gesamte Datei und liest sie in den Speicher. Das -pbedeutet "jede Zeile drucken (hier ist eine" Zeile "die gesamte Datei), nachdem das von gegebene Skript angewendet wurde -e". Das Skript selbst ist ein einfacher Substitutionsoperator. Es erfasst die Zeichenfolge, textgefolgt von 0 oder mehr Leerzeichen, einem =und 0 oder mehr Leerzeichen ( text\s*=\s*) und speichert sie unter $1. Dann wird das erfasste Muster sowie die kürzeste Zeichenfolge in Anführungszeichen durch das Muster ( $1) und ersetzt "". Die sFlagge macht .passende Zeilenumbrüche.

terdon
quelle
Korrektur, -00liest Absätze ein, nicht die ganze Datei ( ref ). Wenn der Text in Anführungszeichen eine Leerzeile enthält, stimmt der reguläre Ausdruck nicht überein.
Glenn Jackman
@glennjackman argh! Ich bekomme die immer durcheinander. . Aus diesem Grund habe ich das doppelt überprüft, indem ich einen zusätzlichen Absatz hinzugefügt und ausgeführt habe perl -00ne 'print;exit'. Und ich habe immer noch die falsche in meine Antwort eingefügt! Danke, jetzt behoben.
Terdon