Pregunta

Tengo un archivo de texto esqueleto con cadenas de marcador de posición:

blah blah blah
blah $PLACEHOLDER_1$
blah
$PLACEHOLDER_2$

y así sucesivamente. & Quot; forma " No importa el número de marcadores de posición, puedo cambiarlos a lo que sea más cómodo para una implementación específica.

Tengo un script de bash donde conozco valores para marcadores de posición, y necesito generar un nuevo archivo, con marcadores de posición reemplazados con 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 múltiples pases con sed, pero no es divertido. Yo 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?

¿Fue útil?

Solución

Todavía puedes usar sed para hacer el reemplazo en una sola pasada. Solo necesita especificar todos los reemplazos en un comando.

por ejemplo.

sed -i 's/PLACEHOLDER_1/string 1/g;s/PLACEHOLDER_2/string 2/g' <file>

Otros consejos

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 bash:

blah blah blah
blah $PLACEHOLDER_1
blah
$PLACEHOLDER_2

Y el guión:

#! /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 puedes 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

Sin sed, sin bucles, solo anidaciones peludas y citas. Estoy bastante seguro de que todas las citas lo protegerán de las cosas maliciosas en un archivo de plantilla, pero no lo voy a garantizar.

Sobre la base de la respuesta anterior, ¿quizás 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é cómo pueden ser las matrices de Bash portátiles. El fragmento de código anterior se probó con "GNU bash, versión 3.2.17 (1) -release (i386-apple-darwin9.0) "

Mi única solución de bash:

TEMPLATE='
foo
$var1
bar
$var2'
eval "echo \"$TEMPLATE\""

Me topé con esta pregunta porque estaba buscando exactamente lo mismo, y encontré envsubst (1) .

Puedes usar envsubst si no te importa 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!)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top