Wie ersetzt man einen mehrzeiligen Code durch sed?

Wie ersetzt man einen mehrzeiligen Code durch sed?

Ich habe eine große Datei, die Sonderzeichen enthält. Darin befindet sich ein mehrzeiliger Code, den ich durch ersetzen möchte sed.

Das:

  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 ohne Erfolg:

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

Es ersetzt nichts und zeigt keine Fehlermeldungen an

Ich habe damit herumgespielt, aber nichts, was ich versuche, funktioniert.

Antwort1

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
  • -0777liest die gesamte Datei auf einmal, nicht Zeile für Zeile

Die Ersetzung s///funktioniert ähnlich wie in sed (d. h. sie gleicht alles ab text = ", gefolgt von allem außer doppelten Anführungszeichen, und zwar viele Male bis hin zu einem doppelten Anführungszeichen), in diesem Fall funktioniert sie jedoch auf die gesamte Datei.

Antwort2

Sie müssen den Musterraum überprüfen und weiterhin die Next-Zeile einfügen, wenn sie nicht übereinstimmt, z. B.

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 allerdings nicht sehr effizient. Besser ist es, einfach den Bereich auszuwählen /text = "/,/"/, die erste Zeile zu ändern und den Rest zu löschen:

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 gnu sedkönnen Sie es als Einzeiler schreiben:

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

Antwort3

"Persönlich würde ich das in Perl machen. Wenn wir davon ausgehen können, dass vor dem schließenden kein steht ", können Sie Folgendes tun:

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

Das -0saugt die gesamte Datei aus und liest sie in den Speicher. Das -pbedeutet „drucke jede Zeile (hier ist eine „Zeile“ die gesamte Datei) nach dem Anwenden des durch -e„“ angegebenen Skripts. 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 als $1. Dann ersetzt es das erfasste Muster sowie die kürzeste zitierte Zeichenfolge, die es findet, durch das Muster ( $1) und "". Das sFlag sorgt für .Übereinstimmung mit Zeilenumbrüchen.

verwandte Informationen