SED über mehrere Leitungen ersetzen

10

Ich versuche diese drei Zeilen zu finden:

<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->

und ersetzen Sie sie durch:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

Wenn ich es versuche

sudo sed -i 's:<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

Es findet es nicht, ich habe auch versucht, es einzufügen, aber es hat immer noch nicht funktioniert:

sudo sed -i 's:<!--\n <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />\n -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

Diese werfen keine Fehler, sie kommentieren die Zeile einfach nicht aus. Jeder Rat würde helfen, danke!

Doug Molineux
quelle

Antworten:

6

sed liest jede Zeile nacheinander, sodass sie niemals mit einem mehrzeiligen Muster übereinstimmt, es sei denn, Sie bewegen sie in die richtige Richtung. Der NBefehl liest eine Zeile aus der Eingabe und hängt sie an den Musterbereich an.

sed -i -e '/^<!--$/ {
    N; /\n<Connector port="8009" protocol="AJP\/1\.3" redirectPort="8443" \/>$/ {
        N; /\n-->$/ {
            s/^<!--\n//; s/\n-->$//
        }
    }
}' /myfile.xml

Wenn Sie einen anderen Befehl als benötigen s, sollten Sie wahrscheinlich von sed zu awk oder perl wechseln. Hier ist ein etwas flexibleres Perl-Snippet, das allgemeiner mit mehrzeiligen Kommentaren umgeht.

perl -i -pe '
    if (/<!--/) { $_ .= <> while !/-->/;
        s[<!--\n(<Connector port="8009" protocol="AJP/1\.3" redirectPort="8443" />)\n-->][$1];
    }' /myfile.xml
Gilles 'SO - hör auf böse zu sein'
quelle
6

Sed arbeitet zeilenweise. Es kann für mehrere Zeilen verwendet werden, aber es wurde nicht so entworfen - und meiner Meinung nach zeigt es definitiv, wenn Sie versuchen, es so zu verwenden. Wenn Sie sich jedoch für diesen Weg entscheiden, müssen Sie wahrscheinlich Register verwenden. Überprüfen Sie einige der Lösungen unter /programming/1251999/sed-how-can-i-replace-a-newline-n, um zu sehen, wie dies durchgeführt werden kann.

Ich bevorzuge es, Perl anstelle von Sed für diese Art von Aufgabe zu verwenden (mehrzeilig, meine ich). Das Boilerplate, das Sie vor dem Suchen und Ersetzen ( BEGIN...) hinzufügen müssen, ist nicht offensichtlich, aber der reguläre Ausdruck scheint mir sauberer zu sein:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--string-->/string/smg' file.xml

Oder verwenden Sie die Gruppierung, um den Ausdruck zu verkürzen und Ihnen zu ermöglichen, dort einen regulären Ausdruck zu verwenden:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--(string_or_regex)-->/\1/smg' file.xml

Es sollte sowohl bei Vorkommen mit als auch ohne Zeilenumbrüche zwischen den Kommentarmarkierungen und dem zu kommentierenden Code funktionieren.

Adaptiert von:

/programming/1030787/multiline-search-replace-with-perl

Eduardo Ivanec
quelle
Vielen Dank für Ihre Hilfe, sieht aus wie es ein Schmerz ist, ich entschied mich für eine Problemumgehung
Doug Molineux
3

Hier ist eine Beschreibung der mehrzeiligen Befehle in SED: http://docstore.mik.ua/orelly/unix/sedawk/ch06_01.htm

Es ist ein Schmerz im Hintern. Vielleicht möchten Sie Eduardos Rat befolgen und perl -i -p -estattdessen verwenden.

Hyppy
quelle
Ich würde nicht auf nicht autorisierte Kopien von urheberrechtlich geschütztem Material verlinken.
Mark Wagner
1
  • /<\!--/ : passende Zeichenfolge
  • :X : Dies ist eine Bezeichnung für den Verzweigungsbefehl "b"
  • /-->/ : passende Zeichenfolge
  • s@...@...@p : Streifen "<! -", "->" und Druckergebnis
  • d : Musterraum löschen und neuen Zyklus starten
  • N : Wenn nicht mit / -> / übereinstimmen, fügen Sie eine Zeile hinzu
  • bX : verzweige zu: X-Label
  • p : Drucke einfach eine Zeichenfolge, die nicht mit / <! - / übereinstimmt

sed -rn '
/<!--/ {
    :X
    /-->/ {
        s@<!--\s*(<.+/>)\s*-->@\1@p
        d
    }
    N
    bX
};p'

und diese zweite Methode ist eine einfache wörtliche Ersetzung durch Kopieren und Einfügen für übliche kleine Textdateien (benötigt eine Shell-Skriptdatei)

#!/bin/bash

# copy & paste content that you want to substitute

AA=$( cat <<\EOF | sed -z -e 's#\([][^$*\.#]\)#\\\1#g' -e 's#\n#\\n#g'
<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->
EOF
)

BB=$( cat <<\EOF | sed -z -e 's#\([&\#]\)#\\\1#g' -e 's#\n#\\n#g'
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
EOF
)

sed -z -i 's#'"${AA}"'#'"${BB}"'#g' *.xml   # apply to all *.xml files
mug896
quelle
1) Vielen Dank für Ihre Antwort. 2) Das Einfügen nur von Codefragmenten ist nicht wirklich in Ordnung. Es wäre viel besser, wenn Sie erklären würden, was es tut und wie.
Peterh - Wiedereinsetzung Monica