¿Cómo reemplazar un código de varias líneas con sed?

¿Cómo reemplazar un código de varias líneas con sed?

Tengo un archivo grande que tiene caracteres especiales. Hay un código de varias líneas allí que quiero reemplazar con sed.

Este:

  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"

Necesita convertirse en esto:

text = ""

Probé el siguiente código, pero no tuve suerte:

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

No reemplaza nada y no muestra ningún mensaje de error.

He estado jugando con él, pero todo lo que intento no funciona.

Respuesta1

Perl al rescate:

perl -i~ -0777 -pe 's/text = "[^"]+"/text = ""/g' input-file
  • -i~editará el archivo "in situ", dejando una copia de seguridad
  • -0777Lee todo el archivo a la vez, no línea por línea.

La sustitución s///funciona de manera similar a sed (es decir, coincide text = "seguido de cualquier cosa menos comillas dobles muchas veces hasta una comilla doble), pero en este caso, funciona en todo el archivo.

Respuesta2

Tienes que verificar el espacio del patrón y seguir tirando de la Nlínea externa si no coincide, por ejemplo.

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

con gnu sedpuedes escribirlo como

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

Sin embargo, eso no es muy eficiente, mejor simplemente seleccione el rango /text = "/,/"/, modifique la primera línea y elimine el resto:

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)

De nuevo, gnu sedpuedes escribirlo en una sola línea:

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

Respuesta3

Personalmente, haría esto en Perl. Si podemos suponer que no hay "antes del cierre ", puedes hacer:

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

Sorbe -0el archivo completo y lo lee en la memoria. Significa -p"imprimir cada línea (aquí, una "línea" será el archivo completo) después de aplicar el script proporcionado por -e". El script en sí es un operador de sustitución simple. Capturará la cadena textseguida de 0 o más espacios en blanco, =y 0 o más espacios en blanco nuevamente ( text\s*=\s*) y la guardará como $1. Luego, reemplazará el patrón capturado, así como la cadena entre comillas más corta que encuentre, con el patrón ( $1) y "". La sbandera hace .coincidir nuevas líneas.

información relacionada