Estoy escribiendo un script para automatizar la creación de archivos de configuración para Apache y PHP para mi propio servidor web. No quiero usar ninguna GUI como CPanel o ISPConfig.
Tengo algunas plantillas de archivos de configuración de Apache y PHP. La secuencia de comandos Bash necesita leer plantillas, realizar sustituciones variables y generar plantillas analizadas en alguna carpeta. ¿Cuál es la mejor manera de hacer eso? Se me ocurren varias maneras. ¿Cuál es el mejor o puede haber algunas formas mejores de hacerlo? Quiero hacer eso en puro Bash (es fácil en PHP, por ejemplo)
1) ¿Cómo reemplazar los marcadores de posición $ {} en un archivo de texto?
template.txt:
the number is ${i}
the word is ${word}
script.sh:
#!/bin/sh
#set variables
i=1
word="dog"
#read in template one line at the time, and replace variables
#(more natural (and efficient) way, thanks to Jonathan Leffler)
while read line
do
eval echo "$line"
done < "./template.txt"
Por cierto, ¿cómo redirecciono la salida a un archivo externo aquí? ¿Necesito escapar de algo si las variables contienen, por ejemplo, comillas?
2) Usando cat & sed para reemplazar cada variable con su valor:
Dado template.txt:
The number is ${i}
The word is ${word}
Mando:
cat template.txt | sed -e "s/\${i}/1/" | sed -e "s/\${word}/dog/"
Me parece mal por la necesidad de escapar de muchos símbolos diferentes y con muchas variables la línea será demasiado larga.
¿Se te ocurre alguna otra solución elegante y segura?
fuente
Respuestas:
Puedes usar esto:
para reemplazar todas las
${...}
cadenas con las variables de entorno correspondientes (no olvide exportarlas antes de ejecutar este script).Para bash puro, esto debería funcionar (suponiendo que las variables no contengan cadenas $ {...}):
. Solución que no se bloquea si RHS hace referencia a alguna variable que se hace referencia a sí misma:
ADVERTENCIA : no conozco una forma de manejar correctamente la entrada con NUL en bash o preservar la cantidad de líneas nuevas finales. La última variante se presenta tal cual es porque los shells "aman" la entrada binaria:
read
interpretará barras invertidas.read -r
no interpretará barras inclinadas invertidas, pero aún caerá la última línea si no termina con una nueva línea."$(…)"
eliminará tantas líneas nuevas finales como haya presentes, así que termino…
con; echo -n a
y usoecho -n "${line:0:-1}"
: esto elimina el último carácter (que esa
) y conserva tantas líneas nuevas finales como había en la entrada (incluyendo no).fuente
[^}]
a[A-Za-Z_][A-Za-z0-9_]
la versión bash para evitar que el shell vaya más allá de la sustitución estricta (por ejemplo, si trató de procesar${some_unused_var-$(rm -rf $HOME)}
).$&
en la solución perl a""
: primero deja${...}
intacta si no puede sustituir, la segunda la reemplaza con una cadena vacía.while
ciclo lea la última línea, incluso si no está terminada por una nueva línea, usewhile read -r line || [[ -n $line ]]; do
. Además, suread
comando elimina los espacios en blanco iniciales y finales de cada línea; para evitar eso, usewhile IFS= read -r line || [[ -n $line ]]; do
\
escaparlas).Tratar
envsubst
fuente
envsubst
no se requiere cuando se usa un heredoc ya que bash trata el heredoc como una cadena literal entre comillas dobles y ya interpola variables en él. Sin embargo, es una gran opción cuando desea leer la plantilla desde otro archivo. Un buen reemplazo para los mucho más engorrososm4
.envsubst
es una utilidad gettext de GNU, y en realidad no es tan robusta (ya que gettext está destinado a localizar mensajes humanos). Lo más importante es que no reconoce las sustituciones $ {VAR} con barra invertida (por lo que no puede tener una plantilla que use sustituciones $ VAR en tiempo de ejecución, como un script de shell o un archivo Nginx conf). Vea mi respuesta para una solución que maneja los escapes de barra invertida.<<"EOF"
, que no interpola variables (los terminadores entre comillas son como las comillas simples de heredocs).cat template.txt | envsubst
envsubst era nuevo para mí. Fantástico.
Para el registro, el uso de un heredoc es una excelente manera de crear una plantilla para un archivo conf.
fuente
envsubst
porque me salvó del adicionalapt-get install gettext-base
en mi DockerfileEstoy de acuerdo con el uso de sed: es la mejor herramienta para buscar / reemplazar. Aquí está mi enfoque:
fuente
-i
opción (editar archivos en su lugar) que es similar a la opción perl . Verifique la página de manual de su sed .Creo que eval funciona muy bien. Maneja plantillas con saltos de línea, espacios en blanco y todo tipo de bash. Si tiene control total sobre las plantillas en sí, por supuesto:
Este método debe usarse con cuidado, por supuesto, ya que eval puede ejecutar código arbitrario. Ejecutar esto como root está prácticamente fuera de discusión. Las citas en la plantilla deben escaparse, de lo contrario se las comerán
eval
.También puede usar aquí los documentos, si lo prefiere
cat
aecho
@plockc provocó una solución que evita el problema de escape de la cita de bash:
Editar: Se eliminó la parte de ejecutar esto como root usando sudo ...
Editar: ¡Se agregó un comentario sobre cómo se deben escapar las citas, se agregó la solución de plockc a la mezcla!
fuente
eval
edecho
/cat
comandos de procesos de ellas; tratareval "echo \"'\$HOME'\""
.Tengo una solución bash como mogsie pero con heredoc en lugar de herejías para permitirle evitar las comillas dobles
fuente
${param:?}
y texto anidado alrededor de parámetros opcionales. Ejemplo: se${DELAY:+<delay>$DELAY</delay>}
expande a nada cuando DELAY no está definido y <delay> 17 </delay> cuando DELAY = 17._EOF_$$
.$trailing_newline
, o usar$NL5
y asegurarse de que se expanda como 5 nuevas líneas.template.txt
funcionaría para preservar las nuevas líneas finales.eval
, sitemplate.txt
contieneEOF
una línea propia, terminará prematuramente el documento aquí y, por lo tanto, romperá el comando. (Punta del sombrero para @xebeche).Editar 6 de enero de 2017
Necesitaba mantener comillas dobles en mi archivo de configuración, por lo que las comillas dobles de escape doble con sed ayudan:
No puedo pensar en seguir líneas nuevas, pero se mantienen líneas vacías en el medio.
Aunque es un tema antiguo, en mi opinión, encontré una solución más elegante aquí: http://pempek.net/articles/2013/07/08/bash-sh-as-template-engine/
Todos los créditos a Grégory Pakosz .
fuente
eval "echo \"$(sed 's/\"/\\"/g' $1)\""
$variables
).En lugar de reinventar la rueda, vaya con envsubst Se puede usar en casi cualquier escenario, por ejemplo, creando archivos de configuración a partir de variables de entorno en contenedores acoplables.
Si en Mac, asegúrese de tener homebrew y luego vincúlelo desde gettext:
./template.cfg
./.env:
./configure.sh
Ahora solo úsalo:
fuente
envsubst
realmente funciona.envsubst
no funciona en MacOS, que había necesidad de instalarlo usando homebrew:brew install gettext
.Una versión más larga pero más robusta de la respuesta aceptada:
Esto expande todas las instancias de
$VAR
o${VAR}
a sus valores de entorno (o, si están definidos, la cadena vacía).Se escapa correctamente de las barras diagonales inversas y acepta un $ escapado de barra invertida para inhibir la sustitución (a diferencia de envsubst, que, al parecer, no hace esto ).
Entonces, si su entorno es:
y tu plantilla es:
el resultado sería:
Si solo desea escapar de las barras invertidas antes de $ (puede escribir "C: \ Windows \ System32" en una plantilla sin cambios), use esta versión ligeramente modificada:
fuente
Lo habría hecho de esta manera, probablemente menos eficiente, pero más fácil de leer / mantener.
fuente
sed -e 's/VARONE/NEWVALA/g' -e 's/VARTWO/NEWVALB/g' -e 's/VARTHR/NEWVALC/g' < $TEMPLATE > $OUTPUT
Si desea usar plantillas Jinja2 , vea este proyecto: j2cli .
Soporta:
fuente
Tomando la respuesta de ZyX usando bash puro pero con un nuevo estilo de coincidencia de expresiones regulares y sustitución indirecta de parámetros se convierte en:
fuente
Si usar Perl es una opción y está contento con basar las expansiones solo en variables de entorno (a diferencia de todas las variables de shell ), considere la respuesta robusta de Stuart P. Bentley .
Esta respuesta tiene como objetivo proporcionar una solución solo para bash que, a pesar del uso de
eval
, debería ser segura de usar .Los objetivos son:
${name}
y$name
variables.$(...)
y sintaxis heredada`...`
)$((...))
y sintaxis heredada$[...]
).\
(\${name}
)."
e\
instancias.Función
expandVars()
:Ejemplos:
${HOME:0:10}
, siempre que no contengan comandos incrustados o sustituciones aritméticas, como${HOME:0:$(echo 10)}
$(
y las`
instancias se escapan a ciegas).${HOME
(falta de cierre}
) ROMPEN la función.\$name
Previene la expansión.\
no seguido por$
se conserva tal cual.\
instancias adyacentes , debe duplicarlas ; p.ej:\\
->\
- lo mismo que solo\
\\\\
->\\
0x1
,0x2
,0x3
.eval
.Si está buscando una solución más restrictiva que solo sea compatible con
${name}
expansiones , es decir, con llaves obligatorias , ignorando$name
referencias, vea esta respuesta mía.Aquí hay una versión mejorada de la
eval
solución libre de bash de la respuesta aceptada :Las mejoras son:
${name}
como$name
variables.\
referencias variables de escape que no deberían expandirse.eval
solución basada anteriormente,fuente
Aquí hay otra solución de bash puro:
$ cat code
$ cat template
(con líneas finales y comillas dobles)salida
fuente
Aquí hay otra solución: generar un script bash con todas las variables y el contenido del archivo de plantilla, ese script se vería así:
Si introducimos este script en bash, produciría el resultado deseado:
Aquí se explica cómo generar ese script y alimentar ese script en bash:
Discusión
cat
comando con HEREDOCSi desea redirigir esta salida a un archivo, reemplace la última línea con:
fuente
Esta página describe una respuesta con awk
fuente
Estuche perfecto para shtpl . (proyecto mío, por lo que no se usa mucho y carece de documentación. Pero aquí está la solución que ofrece de todos modos. Puede que desee probarlo).
Solo ejecuta:
El resultado es:
Que te diviertas.
fuente
Esta es la función de bash puro ajustable a su gusto, utilizada en producción y no debe interrumpirse en ninguna entrada. Si se rompe, avíseme.
fuente
También puede usar bashible (que internamente usa el enfoque de evaluación descrito arriba / abajo).
Hay un ejemplo, cómo generar un HTML a partir de múltiples partes:
https://github.com/mig1984/bashible/tree/master/examples/templates
fuente
Aquí hay una función bash que conserva los espacios en blanco:
fuente
Aquí hay una
perl
secuencia de comandos modificada basada en algunas de las otras respuestas:Características (basadas en mis necesidades, pero deberían ser fáciles de modificar):
fuente
Mira el script de Python de sustitución de variables simples aquí: https://github.com/jeckep/vsubst
Es muy facíl de usar:
fuente
Mi humilde contribución a esta maravillosa pregunta.
Básicamente, esto funciona al usar la subshell para hacer el reemplazo de envar, excepto que no usa eval y escapa explícitamente a comillas simples y dobles. Concatena las expresiones var en una sola línea sin espacios para no confundir
sh
y luego pasa la plantilla aecho
, permitiendosh
manejar los reemplazos var. Conserva nuevas líneas, comentarios, etc. y puede escapar\${like_this}
si no desea que se interprete la var.${missing_var}
solo se reemplazará con un valor vacío.Muchas de las otras respuestas aquí son muy buenas, pero quería algo muy simple y no necesita manejar literalmente todos los casos posibles para los casos de plantillas que tengo actualmente.
¡Disfrutar!
fuente
Para dar seguimiento a la respuesta de plockc en esta página, aquí hay una versión adecuada para el tablero, para aquellos de ustedes que buscan evitar los bashismos.
fuente
No puede ser más simple que:
$ persona = Bob ./render template.txt >dered.txt
Ver https://github.com/relaxdiego/renderest
fuente