SED reemplazar en varias líneas

11

Estoy tratando de encontrar estas tres líneas:

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

y reemplazarlos con:

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

Cuando lo intento

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

No lo encuentra, también intenté poner \ n en él, pero aún no funcionó:

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

Estos no arrojan ningún error, simplemente no descomenta la línea. Cualquier consejo ayudaría, gracias!

Doug Molineux
fuente

Respuestas:

6

sed lee cada línea por turno, por lo que nunca coincidirá con un patrón multilínea a menos que lo empuje en la dirección correcta. El Ncomando lee una línea de la entrada y la agrega al espacio del patrón.

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

Podría decirse que si necesita un comando que no sea s, entonces debe cambiar de sed a awk o perl. Aquí hay un fragmento de Perl un poco más flexible que hace frente a comentarios multilínea de una manera más general.

perl -i -pe '
    if (/<!--/) { $_ .= <> while !/-->/;
        s[<!--\n(<Connector port="8009" protocol="AJP/1\.3" redirectPort="8443" />)\n-->][$1];
    }' /myfile.xml
Gilles 'SO- deja de ser malvado'
fuente
6

Sed trabaja línea por línea. Se puede hacer que funcione en varias líneas, pero no se diseñó de esa manera, y en mi opinión, definitivamente se muestra cuando intentas usar así. Pero si decide seguir ese camino, probablemente tendrá que usar registros. Consulte algunas de las soluciones a /programming/1251999/sed-how-can-i-replace-a-newline-n para ver cómo se puede hacer.

Prefiero usar perl en lugar de sed para este tipo de tarea (quiero decir, orientado a varias líneas). La repetitiva que debe agregar antes de search-and-replace ( BEGIN...) no es obvia, pero la expresión regular me parece más limpia:

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

O, usando la agrupación para acortar la expresión y permitirle usar una expresión regular allí:

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

Debería funcionar tanto en casos con y sin nuevas líneas entre los marcadores de comentarios y el código que no se comentará.

Adaptado de:

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

Eduardo Ivanec
fuente
Gracias por su ayuda, parece que es un dolor, decidí usar una solución alternativa
Doug Molineux
3

Aquí hay una descripción de los comandos multilínea en SED: http://docstore.mik.ua/orelly/unix/sedawk/ch06_01.htm

Es un dolor en el trasero. Es posible que desee seguir los consejos de Eduardo y usarlos perl -i -p -een su lugar.

Hippy
fuente
No enlazaría a copias no autorizadas de material con derechos de autor.
Mark Wagner
1
  • /<\!--/ : cadena coincidente
  • :X : esta es una etiqueta para el comando de rama "b"
  • /-->/ : cadena coincidente
  • s@...@...@p : tira "<! -", "->" e imprime el resultado
  • d : borra el espacio del patrón y comienza un nuevo ciclo
  • N : si no coincide con / -> / luego agregue una línea
  • bX : ramifica a: etiqueta X
  • p : simplemente imprime una cadena que no coincide con / <! - /

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

y este segundo método es una simple sustitución literal de copiar y pegar para archivos de texto de tamaño pequeño (se necesita un archivo de script de shell)

#!/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
fuente
1) Gracias por tu respuesta. 2) Insertar solo fragmentos de código no está realmente bien, sería mucho mejor si explicaras qué hace y cómo.
peterh - Restablece a Mónica el