Reemplazar cadena multilínea en archivos

17

Tengo una serie de archivos que quiero actualizar reemplazando una cadena de varias líneas con otra cadena de varias líneas. Algo en la línea de:

* Some text, 
* something else
* another thing

Y quiero reemplazarlo con:

* This is completely
* different text

El resultado sería que después del reemplazo, el archivo que contiene el primer bloque de texto ahora contendrá la segunda cadena (el resto del archivo no cambia).

Parte del problema es que tengo que encontrar la lista de archivos que se actualizarán en el sistema de archivos. Supongo que puedo usar grep para eso (aunque, de nuevo, eso no es tan fácil de hacer con cadenas multilínea) y luego conectarlo en sed, ¿tal vez?

¿Hay una forma fácil de hacer esto? Sed es una opción, pero es incómodo porque tengo que agregar \ n, etc. ¿Hay alguna forma de decir "tomar la entrada de este archivo, emparejarla en esos archivos y luego reemplazarla por el contenido de este otro archivo"? Puedo usar Python si es necesario, pero quiero algo rápido y simple, así que si hay una utilidad disponible, prefiero usarla que escribir mi propio script (que sé cómo hacer).

ventsyv
fuente
Probablemente deberías usar perl para esto. stackoverflow.com/questions/1030787/…
orion
3
Entonces, ¿quieres hacer coincidir some text, something else another thingsi abarca o no varias líneas? ¿O solo quieres unir some text,\nsomething else\nanotherthing?
mikeserv
2
Edite su pregunta y aclare cuál es exactamente el contenido de cada archivo y cuál es el resultado deseado.
jimmij
La cadena abarca varias líneas. Prefiero ignorar el espacio en blanco al hacer coincidir / reemplazar porque podría no ser todo lo mismo, pero no es un gran problema si solo hago 1-1 (nuevas líneas y todo).
ventsyv

Respuestas:

12

Sustituya "Some ... \ n ... Thing" por el contenido del archivo "new" en uno o más archivos de entrada

perl -i -p0e 's/Some.*?thing\n/`cat new`/se' input.txt ...
  1. -i para cambiar input.txt directamente
  2. -p0 sorber el archivo de entrada e imprimirlo al final
  3. s/regexp/.../s en regexp .es.|\n
  4. s/.../exp/e sustituir por eval(exp)
  5. nuevo: un archivo que contiene el texto de reemplazo (Esto es completamente ... texto diferente)
  6. si es útil, puede expandir el texto original s/Some text\n...\n...thing\n/...
JJoao
fuente
¿Cómo puedo hacer lo mismo con un archivo llamado say "before" para buscar el contenido (de varias líneas) de ese archivo? Lo intenté pero no funciona.
Kvothe
@Kvothe, necesitamos más detalles ... Suponiendo que "antes" no tenga caracteres especiales, puede intentarloperl -i -p0e ' $b= `cat before`; s/$b/Some thing\n/se' input.txt ...
JJoao
Y suponiendo que el "antes" contiene todos los caracteres especiales (nuevas líneas, barras, corchetes) excepto 'y'.
Kvothe
5
sed -e :n -e '$!N;/\n.*\n/!{$!bn
};  s/some text,\n* *something else\n* *another thing/this is completely\
different text/;P;D' <infile

Me temo que va a tener dificultades para encontrar una solución que se adapte a usted hasta que elabore una descripción concreta del problema, pero eso es lo que el QA es más adecuado, según lo veo. Tal vez esto le dará una idea: siempre mantendrá 3 líneas en el espacio del patrón a la vez, con una anticipación de 2 líneas, mientras se desliza hacia adelante a través del archivo de entrada solo una línea a la vez.

Debe poder hacer coincidir su cadena, ya sea que abarque varias líneas o no, hasta tres, es decir. Pero no hay disposiciones para reflejar esa disposición en el reemplazo; siempre abarca dos líneas tal como están escritas.

mikeserv
fuente
0

No es muy fuerte (porque no cheches la segunda cuerda pero es fácil de asentar) y puede ser que no sea compatible con posix, pero es muy simple:

sed '/^Some text/{:1;/another thing$/!{N;b 1}
     s/.*/this is completely\ndifferent text/g}' input.txt

El primer comando agrega líneas desde Algún texto hasta que haya encontrado otra cosa, luego la segunda línea lo cambia a otro texto.

NOTA La limitación es que algún texto siempre debe ir seguido de otra cosa .

Costas
fuente
El problema es que la cadena podría ser más de 2 líneas (hasta una docena o más) y puede contener otras cosas que necesitan fuerzas que se escapó, por ejemplo, pestañas, etc. *
ventsyv
@ventsyv No hay problema con el número de líneas o separadores: el script comprueba solo el inicio y el final. Es suficiente si la cadena de inicio es excepcionalmente puede marcar texto para cambiar . Si no es mejor, muestre el ejemplo de entrada para producir el patrón correcto.
Costas