Tengo varios archivos de texto en los que he introducido variables de shell ($ VAR1 o $ VAR2, por ejemplo).
Me gustaría tomar esos archivos (uno por uno) y guardarlos en archivos nuevos donde todas las variables habrían sido reemplazadas.
Para hacer esto, utilicé el siguiente script de shell (que se encuentra en StackOverflow):
while read line
do
eval echo "$line" >> destination.txt
done < "source.txt"
Esto funciona muy bien en archivos muy básicos.
Pero en archivos más complejos, el comando "eval" hace demasiado:
Las líneas que comienzan con "#" se omiten
El análisis de archivos XML da como resultado toneladas de errores
Hay una mejor manera de hacerlo? (en el script de shell ... sé que esto se hace fácilmente con Ant, por ejemplo)
Saludos cordiales

envsubstes parte de GNU gettextsource.txtcontiene$caracteres fuera de la expansión variable,envsubsttambién los reemplazará y no hay forma de escapar del$. La solución común (fea) esexport DOLLAR="$".En referencia a la respuesta 2, al hablar de envsubst, preguntaste:
La respuesta es que simplemente necesita exportar sus variables antes de llamar
envsubst.También puede limitar las cadenas de variables que desea reemplazar en la entrada usando el
envsubstSHELL_FORMATargumento (evitando el reemplazo involuntario de una cadena en la entrada con un valor de variable de shell común, por ejemplo$HOME).Por ejemplo:
export VAR1='somevalue' VAR2='someothervalue' MYVARS='$VAR1:$VAR2' envsubst "$MYVARS" <source.txt >destination.txtReemplazará todas las instancias de
$VAR1y$VAR2(y soloVAR1yVAR2) ensource.txtcon'somevalue'y'someothervalue'respectivamente.fuente
'que se utilizan para establecerMYVARSson crucialesexport,envsubsto cualquier comando de entrelazado puede fallar cuando el texto a sustituir es grande. Referencia.SHELL_FORMATargumento (es decir"$MYVARS") hace que todas las variables exportadas sean sustituidas. Si eso es lo que necesita, no se preocupe.Sé que este tema es antiguo, pero tengo una solución de trabajo más simple sin exportar las variables. Puede ser un delineador, pero prefiero dividir usando
\el final de la línea.var1='myVar1'\ var2=2\ var3=${var1}\ envsubst '$var1,$var3' < "source.txt" > "destination.txt" # ^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^ # define which to replace input outputLas variables deben definirse en la misma línea que
envsubstpara ser consideradas como variables de entorno.El
'$var1,$var3'es opcional para reemplazar solo los especificados. Imagínese un archivo de entrada${VARIABLE_USED_BY_JENKINS}que no debería ser reemplazado.fuente
$ export MY_ENV_VAR=congratulation$MY_ENV_VARTambién puede usar todas las demás variables ENV definidas por su sistema como (en linux) $ TERM, $ SHELL, $ HOME ...
$ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" < in.txt > out.txty debería ver "felicitaciones".
fuente
Si realmente solo desea usar bash (y sed), entonces revisaría cada una de sus variables de entorno (como las devuelve
seten modo posix) y construiría un montón de-e 'regex'for sed a partir de eso, terminado por a-e 's/\$[a-zA-Z_][a-zA-Z0-9_]*//g', luego pasaría todo eso a sed.Sin embargo, Perl haría un mejor trabajo, tiene acceso a las variables de entorno como una matriz y puede hacer reemplazos ejecutables para que solo coincida con cualquier variable de entorno una vez.
fuente
perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' "$main_tf_file"En realidad, debe cambiar su
reada,read -rlo que hará que ignore las barras invertidas.Además, debe escapar de las comillas y las barras invertidas. Entonces
while read -r line; do line="${line//\\/\\\\}" line="${line//\"/\\\"}" line="${line//\`/\\\`}" eval echo "\"$line\"" done > destination.txt < source.txtSin embargo, sigue siendo una forma terrible de hacer expansión.
fuente
Exporte todas las variables necesarias y luego use un Perl Onliner
TEXT=$(echo "$TEXT"|perl -wpne 's#\${?(\w+)}?# $ENV{$1} // $& #ge;')Esto reemplazará todas las variables ENV presentes en TEXT con valores reales. Las citas también se conservan :)
fuente
Si desea que las variables env se reemplacen en sus archivos de origen mientras mantiene todas las variables que no son env como están, puede usar el siguiente comando:
envsubst "$(printf '${%s} ' $(env | sed 's/=.*//'))" < source.txt > destination.txtAquí se explica la sintaxis para reemplazar solo variables específicas . El comando anterior usa un sub-shell para listar todas las variables definidas y luego pasarlo al
envsubstEntonces, si hay una variable env definida llamada
$NAME, y susource.txtarchivo se ve así:Hello $NAME Your balance is 123 ($USD)El
destination.txtserá:Hello Arik Your balance is 123 ($USD)Observe que
$NAMEse reemplaza y$USDse deja intactofuente
Llame al binario de perl, en el modo de búsqueda y reemplazo por línea (the
-pi) ejecutando el código perl (the-e) entre comillas simples, que itera sobre las claves del%ENVhash especial que contiene los nombres de las variables exportadas como claves y los valores de las variables exportadas como los valores de las claves y para cada iteración simple reemplace una cadena que contenga un$<<key>>con su<<value>>.perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' fileAdvertencia: se requiere un manejo lógico adicional para los casos en los que dos o más vars comienzan con la misma cadena ...
fuente
envsubstparece exactamente algo que quería usar, pero la-vopción me sorprendió un poco.Si
envsubst < template.txtbien funcionaba bien, lo mismo con la opción-vno funcionaba:Como escribí, esto no estaba funcionando:
Tuve que hacer esto para que funcione:
Quizás ayude a alguien.
fuente