bash - variable - Rellenar marcadores de posición en el archivo en un solo pase
sed replace a string with another (5)
Tengo un archivo de texto esqueleto con cadenas de marcador de posición:
blah blah blah
blah $PLACEHOLDER_1$
blah
$PLACEHOLDER_2$
y así. La "forma" específica de marcadores de posición no importa; puedo cambiarlos a lo que sea más cómodo para una implementación específica.
Tengo un script bash donde conozco los valores de los marcadores de posición, y necesito generar un nuevo archivo, con marcadores de posición reemplazados por valores.
#! /bin/sh
PLACEHOLDER_1 = ''string 1''
PLACEHOLDER_2 = ''multiline
string
2''
# TODO: Generate file output.txt from file output.template
# using placeholders above.
Puedo hacer esto en pases múltiples con sed, pero no es divertido. No quiero usar Perl. Quiero usar textutils y bash solo.
¿Cuál es la mejor manera de hacer lo que quiero en una sola pasada?
Sobre la base de la respuesta anterior, ¿tal vez usar una matriz y calcular la cadena sed?
#!/bin/sh
PLACEHOLDER[0]=''string 1''
PLACEHOLDER[1]=''multiline
string
2''
s="sed -i "
for(( i=0 ; i<${#PLACEHOLDER[*]} ; i++ )) ; do
echo ${PLACEHOLDER[$i]}
s=$s"s/PLACEHOLDER_$i/${PLACEHOLDER[$i]}/g;"
done
echo $s
Sin embargo, parece fallar en las cadenas de varias líneas.
No sé qué tan portátiles pueden ser las matrices de Bash. Por encima del fragmento probado con "GNU bash, versión 3.2.17 (1) -release (i386-apple-darwin9.0)"
Todavía puede usar sed para hacer el reemplazo en una sola pasada. Solo necesita especificar todos los reemplazos en un comando.
p.ej.
sed -i ''s/PLACEHOLDER_1/string 1/g;s/PLACEHOLDER_2/string 2/g'' <file>
Aquí hay una manera de hacerlo sin sed:
Primero, un archivo de plantilla ligeramente modificado en el que los marcadores de posición son variables de bash:
blah blah blah
blah $PLACEHOLDER_1
blah
$PLACEHOLDER_2
Y el guion:
#! /bin/sh
templatefile=output.template
outputfile=output.txt
PLACEHOLDER_1=''string 1''
PLACEHOLDER_2=''multiline
string
2''
# DONE: Generate file output.txt from file output.template
# using placeholders above.
echo "$(eval "echo /"$(cat $templatefile)/"")" > $outputfile
Aquí hay una versión que muestra una plantilla contenida en el script, pero con un giro. También muestra los valores predeterminados, que también se pueden usar en la versión del archivo de plantilla, además de que puede hacer cálculos matemáticos en la plantilla:
#! /bin/sh
template=''blah blah blah
blah $PLACEHOLDER_1
blah
${PLACEHOLDER_2:-"some text"} blah ${PLACEHOLDER_3:-"some
lines
of
text"} and the total is: $((${VAL_1:-0} + ${VAL_2:-0}))''
# default operands to zero (or 1) to prevent errors due to unset variables
outputfile=output.txt
# gears spin, bells ding, values for placeholders are computed
PLACEHOLDER_1=''string 1''
PLACEHOLDER_2=''multiline
string
2''
VAL_1=2
VAL_2=4
unset PLACEHOLDER_3 # so we can trigger one of the defaults
# Generate file output.txt from variable $template
# using placeholders above.
echo "$(eval "echo /"$template/"")" > $outputfile
No sed, no loops, solo anidamiento peludo y citas. Estoy bastante seguro de que todas las citas lo protegerán de cosas maliciosas en un archivo de plantilla, pero no voy a garantizarlo.
Mi única solución bash:
TEMPLATE=''
foo
$var1
bar
$var2''
eval "echo /"$TEMPLATE/""
Acabo de tropezar con esta pregunta porque estaba buscando exactamente lo mismo, y encontré envsubst(1)
.
Puede usar envsubst si no le molesta usar variables de entorno:
PLACEHOLDER_1=''string 1'' PLACEHOLDER_2=''multiline
string
2'' envsubst < output.template
Si tiene muchas variables, puede almacenarlas en un archivo y simplemente source
(¡recuerde usar export
al final del archivo de origen!)