¿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?

smokris
fuente

Respuestas:

36
lead='^### BEGIN GENERATED CONTENT$'
tail='^### END GENERATED CONTENT$'
sed -e "/$lead/,/$tail/{ /$lead/{p; r insert_file
        }; /$tail/p; d }"  existing_file
Peter.O
fuente
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
smokris
fuente
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
Dr. Kitty
fuente
¿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
Jetchisel
fuente
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