¿Cómo reemplazar parte de un archivo de texto entre marcadores con otro archivo de texto?


26

Digamos que tengo un archivo de texto como este:

# custom content section
a
b

### BEGIN GENERATED CONTENT
c
d
### END GENERATED CONTENT

Me gustaría reemplazar la parte entre las GENERATED CONTENTetiquetas con el contenido de otro archivo.

¿Cuál es la forma más sencilla de hacer esto?

Respuestas:


36
lead='^### BEGIN GENERATED CONTENT$'
tail='^### END GENERATED CONTENT$'
sed -e "/$lead/,/$tail/{ /$lead/{p; r insert_file
        }; /$tail/p; d }"  existing_file

Excelente. sed¡puede hacer mucho más que solo s/.../...!
DevSolar

Hmmm no funciona para mí, ¿debería poner el comando sed en una línea?
lzap

3
El r insert_filecomando debe ser lo último en su línea. Tenga en cuenta que ni los espacios en blanco ni los comentarios están permitidos después. El código se probó usando GNU sedcon la --posixopción habilitada, y funcionó como se esperaba, por lo que debería funcionar con cualquier posix compatible sed .
Peter.O

1
Santo Moly, eso es genial! ¡Esto va en mi diccionario sed! Muy útil y bellamente simple. ¡Gracias!
DanielSmedegaardBuus

2
Tenga en cuenta que una edición en el lugar requiere que capture la salida de sed (p output=$(sed -e "..." existing_file). Ej. ) Y luego realice el reemplazo en una segunda pasada (p echo "$output" > existing_file. Ej. ), Ya que al intentar redirigir a un archivo desde el que está leyendo, se truncará antes de leer el contenido.
Chris Tonkinson el

5
newContent=`cat new_file`
perl -0777 -i -pe "s/(### BEGIN GENERATED CONTENT\\n).*(\\n### END GENERATED CONTENT)/\$1$newContent\$2/s" existing_file

Buen trabajo. Mucho más simple que el mío. :)
Dr Kitty

4

Advertencia: definitivamente esta no es la forma más sencilla de hacerlo. (EDITAR: bash funciona; POSIX grep también está bien)

Si el texto principal está en el archivo "main" y el contenido generado está en el archivo "gen", puede hacer lo siguiente:

#!/bin/bash
BEGIN_GEN=$(cat main | grep -n '### BEGIN GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
END_GEN=$(cat main | grep -n '### END GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g')
cat <(head -n $(expr $BEGIN_GEN - 1) main) gen <(tail -n +$(expr $END_GEN + 1) main) >temp
mv temp main

¿Esto funciona? Creo que su última línea se abrirá mainpara escribir, borrarla, antes de que cat la lea.
chepner

@chepner Crap, tienes razón. El resto funciona, sin embargo. Lo arreglaré.
Dr. Kitty

3
ed -s FILE1 <<EOF
/### BEGIN GENERATED/+,/### END GENERATED/-d
/### BEGIN GENERATED/ r FILE2
w
q
EOF

Usando un heredoc y el editor de línea ed. La primera línea dentro del heredoc es eliminar 'd' la línea después de '+' el '### BEGIN GENERATED ...' y la línea antes de '-' el '### END GENERATED ...' la segunda línea es insertar FILE2 después de la línea ### END GENERATED ... '
Jetchisel

lo siento, lo que quise decir fue insertar FILE2 después de la línea '### BEGIN GENERATED ..'
Jetchisel

Tómelo con calma amigos, después de todo es mi primera vez :-). También podría haber usado la misma palabra, pero la otra solución no usa un heredocs sino un printf y una tubería. De cualquier manera, me
disculpo

Gracias, muy legible! Por cierto, en lugar de r FILE2que pueda decir r !commandque lea desde un guión diferente.
Kos
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.