Pregunta

Quiero canalizar la salida de una " plantilla " en MySQL, el archivo tiene variables como $ {dbName} intercaladas. ¿Cuál es la utilidad de línea de comando para reemplazar estas instancias y volcar la salida a salida estándar?

¿Fue útil?

Solución

Sed !

Dado template.txt:

The number is ${i}
The word is ${word}

solo tenemos que decir:

sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt

Gracias a Jonathan Leffler por el consejo de pasar múltiples argumentos -e a la misma invocación sed .

Otros consejos

Actualizar

Aquí hay una solución de yottatsa en una pregunta similar que solo reemplaza variables como $ VAR o $ {VAR }, y es un breve resumen

i=32 word=foo envsubst < template.txt

Por supuesto, si i y word están en su entorno, entonces es solo

envsubst < template.txt

En mi Mac, parece que se instaló como parte de gettext y de MacGPG2

Respuesta anterior

Aquí hay una mejora en la solución de mogsie en una pregunta similar, mi solución no requiere que escales el doble citas, lo hace mogsie, pero el suyo es de una sola línea!

eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null

El poder de estas dos soluciones es que solo obtienes algunos tipos de expansiones de shell que normalmente no ocurren $ ((...)), `...`, y $ (...), aunque La barra invertida es un personaje de escape aquí, pero no tiene que preocuparse de que el análisis tenga un error y haga varias líneas muy bien.

Utilice / bin / sh . Cree un pequeño script de shell que establezca las variables y luego analice la plantilla utilizando el propio shell. Me gusta (edita para manejar las nuevas líneas correctamente):

Archivo template.txt:

the number is ${i}
the word is ${word}

Archivo 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"

Salida:

#sh script.sh
the number is 1
the word is dog

Estaba pensando en esto nuevamente, dado el interés reciente, y creo que la herramienta en la que originalmente pensaba era m4 , el procesador de macros para autotools. Entonces, en lugar de la variable que especifiqué originalmente, usaría:

$echo 'I am a DBNAME' | m4 -DDBNAME="database name"

template.txt

Variable 1 value: ${var1}
Variable 2 value: ${var2}

data.sh

#!/usr/bin/env bash
declare var1="value 1"
declare var2="value 2"

parser.sh

#!/usr/bin/env bash

# args
declare file_data=$1
declare file_input=$2
declare file_output=$3

source $file_data
eval "echo \"$(< $file_input)\"" > $file_output
  

./parser.sh data.sh template.txt parsed_file.txt

parsed_file.txt

Variable 1 value: value 1
Variable 2 value: value 2

aquí está mi solución con perl basada en la respuesta anterior, reemplaza las variables de entorno:

perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile

Aquí hay una función robusta de Bash que, a pesar de usar eval , debería ser segura de usar.

Todas las referencias de variable $ {varName} en el texto de entrada se expanden en función de las variables del shell que llama.

Nada más se expande: ninguna de las referencias de variables cuyos nombres son no se encuentra dentro de {...} (como $ varName ), ni sustituciones de comandos ( $ (...) y sintaxis heredada `...` ), ni sustituciones aritméticas ( $ ( (...)) y la sintaxis heredada $ [...] ).

Para tratar un $ como un literal, \ -escape it; por ejemplo: \ $ {HOME}

Tenga en cuenta que la entrada solo se acepta a través de stdin .

Ejemplo :

$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and \$(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)

Código fuente de la función:

expandVarsStrict(){
  local line lineEscaped
  while IFS= read -r line || [[ -n $line ]]; do  # the `||` clause ensures that the last line is read even if it doesn't end with \n
    # Escape ALL chars. that could trigger an expansion..
    IFS= read -r -d '' lineEscaped < <(printf %s "$line" | tr '`([

La función asume que no hay caracteres de control 0x1 , 0x2 , 0x3 y 0x4 Presente en la entrada, porque esos caracteres. se usan internamente, ya que la función procesa texto , eso debería ser una suposición segura.

'\1\2\3\4') # ... then selectively reenable ${ references lineEscaped=${lineEscaped//

La función asume que no hay caracteres de control 0x1 , 0x2 , 0x3 y 0x4 Presente en la entrada, porque esos caracteres. se usan internamente, ya que la función procesa texto , eso debería ser una suposición segura.

\4'{/\${} # Finally, escape embedded double quotes to preserve them. lineEscaped=${lineEscaped//\"/\\\"} eval "printf '%s\n' \"$lineEscaped\"" | tr '\1\2\3\4' '`([

La función asume que no hay caracteres de control 0x1 , 0x2 , 0x3 y 0x4 Presente en la entrada, porque esos caracteres. se usan internamente, ya que la función procesa texto , eso debería ser una suposición segura.

done }

La función asume que no hay caracteres de control 0x1 , 0x2 , 0x3 y 0x4 Presente en la entrada, porque esos caracteres. se usan internamente, ya que la función procesa texto , eso debería ser una suposición segura.

Si está abierto a usar Perl , esa sería mi sugerencia. Aunque probablemente hay algunos sed y / o AWK expertos que probablemente saben cómo hacerlo mucho más fácilmente. Si tiene un mapeo más complejo con más que solo dbName para sus reemplazos, podría extender esto con bastante facilidad, pero también podría incluirlo en un script Perl estándar en ese momento.

perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql

Un script corto en Perl para hacer algo un poco más complicado (manejar múltiples claves):

#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/\$\{

Si está abierto a usar Perl , esa sería mi sugerencia. Aunque probablemente hay algunos sed y / o AWK expertos que probablemente saben cómo hacerlo mucho más fácilmente. Si tiene un mapeo más complejo con más que solo dbName para sus reemplazos, podría extender esto con bastante facilidad, pero también podría incluirlo en un script Perl estándar en ese momento.

perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql

Un script corto en Perl para hacer algo un poco más complicado (manejar múltiples claves):

replace-script < yourfile | mysql

Si nombra la secuencia de comandos anterior como reemplazo de secuencia de comandos, podría utilizarse de la siguiente manera:

<*>\}/$replace{

Si está abierto a usar Perl , esa sería mi sugerencia. Aunque probablemente hay algunos sed y / o AWK expertos que probablemente saben cómo hacerlo mucho más fácilmente. Si tiene un mapeo más complejo con más que solo dbName para sus reemplazos, podría extender esto con bastante facilidad, pero también podría incluirlo en un script Perl estándar en ese momento.

perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql

Un script corto en Perl para hacer algo un poco más complicado (manejar múltiples claves):

<*>

Si nombra la secuencia de comandos anterior como reemplazo de secuencia de comandos, podría utilizarse de la siguiente manera:

<*>}/g for keys %replace; print $buf;

Si nombra la secuencia de comandos anterior como reemplazo de secuencia de comandos, podría utilizarse de la siguiente manera:

<*>

Crear rendertemplate.sh :

#!/usr/bin/env bash

eval "echo \"$(cat $1)\""

Y template.tmpl :

Hello, ${WORLD}
Goodbye, ${CHEESE}

Renderiza la plantilla:

$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl 
Hello, Foo
Goodbye, Bar

file.tpl:

The following bash function should only replace ${var1} syntax and ignore 
other shell special chars such as `backticks` or $var2 or "double quotes". 
If I have missed anything - let me know.

script.sh:

template(){
    # usage: template file.tpl
    while read -r line ; do
            line=${line//\"/\\\"}
            line=${line//\`/\\\`}
            line=${line//\$/\\\$}
            line=${line//\\\${/\${}
            eval "echo \"$line\""; 
    done < ${1}
}

var1="*replaced*"
var2="*not replaced*"

template file.tpl > result.txt

Sugeriría usar algo como Sigil :      https://github.com/gliderlabs/sigil

Se compila en un solo binario, por lo que es extremadamente fácil de instalar en los sistemas.

Entonces puede hacer una línea simple como la siguiente:

cat my-file.conf.template | sigil -p $(env) > my-file.conf

Esto es mucho más seguro que eval y más fácil que usar expresiones regulares o sed

Encontré este hilo mientras me preguntaba lo mismo. Me inspiró a esto (cuidado con los backticks)

$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world

Hay muchas opciones aquí, pero pensé que tiraría la mía al montón. Se basa en Perl, solo se dirige a variables de la forma $ {...}, toma el archivo para procesarlo como un argumento y genera el archivo convertido en la salida estándar:

use Env;
Env::import();

while(<>) { 

Hay muchas opciones aquí, pero pensé que tiraría la mía al montón. Se basa en Perl, solo se dirige a variables de la forma $ {...}, toma el archivo para procesarlo como un argumento y genera el archivo convertido en la salida estándar:

<*>

Por supuesto que no soy una persona perl, así que podría haber un error fatal (aunque funciona para mí).

=~ s/(\${\w+})/$1/eeg; $text .=

Hay muchas opciones aquí, pero pensé que tiraría la mía al montón. Se basa en Perl, solo se dirige a variables de la forma $ {...}, toma el archivo para procesarlo como un argumento y genera el archivo convertido en la salida estándar:

<*>

Por supuesto que no soy una persona perl, así que podría haber un error fatal (aunque funciona para mí).

; } print "$text";

Por supuesto que no soy una persona perl, así que podría haber un error fatal (aunque funciona para mí).

Se puede hacer en bash si tiene el control del formato del archivo de configuración. Solo necesita obtener (". & Quot;) el archivo de configuración en lugar de subshell. Eso asegura que las variables se creen en el contexto del shell actual (y continúen existiendo) en lugar de la subshell (donde la variable desaparece cuando la subshell sale).

$ cat config.data
    export parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA
    export parm_user=pax
    export parm_pwd=never_you_mind

$ cat go.bash
    . config.data
    echo "JDBC string is " $parm_jdbc
    echo "Username is    " $parm_user
    echo "Password is    " $parm_pwd

$ bash go.bash
    JDBC string is  jdbc:db2://box7.co.uk:5000/INSTA
    Username is     pax
    Password is     never_you_mind

Si su archivo de configuración no puede ser un script de shell, puede simplemente 'compilarlo' antes de ejecutarlo (la compilación depende de su formato de entrada).

$ cat config.data
    parm_jdbc=jdbc:db2://box7.co.uk:5000/INSTA # JDBC URL
    parm_user=pax                              # user name
    parm_pwd=never_you_mind                    # password

$ cat go.bash
    cat config.data
        | sed 's/#.*$//'
        | sed 's/[ \t]*$//'
        | sed 's/^[ \t]*//'
        | grep -v '^

En su caso específico, podría usar algo como:

$ cat config.data
    export p_p1=val1
    export p_p2=val2
$ cat go.bash
    . ./config.data
    echo "select * from dbtable where p1 = '$p_p1' and p2 like '$p_p2%' order by p1"
$ bash go.bash
    select * from dbtable where p1 = 'val1' and p2 like 'val2%' order by p1

Luego canaliza la salida de go.bash a MySQL y listo, espero que no destruyas tu base de datos :-).

| sed 's/^/export ' >config.data-compiled . config.data-compiled echo "JDBC string is " $parm_jdbc echo "Username is " $parm_user echo "Password is " $parm_pwd $ bash go.bash JDBC string is jdbc:db2://box7.co.uk:5000/INSTA Username is pax Password is never_you_mind

En su caso específico, podría usar algo como:

<*>

Luego canaliza la salida de go.bash a MySQL y listo, espero que no destruyas tu base de datos :-).

Esta es una forma de hacer que el shell haga la sustitución por ti, como si el contenido del archivo se escribiera entre comillas dobles.

Usando el ejemplo de template.txt con contenido:

The number is ${i}
The word is ${word}

La siguiente línea hará que el shell interpole el contenido de template.txt y escriba el resultado en una salida estándar.

i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'

Explicación:

  • i y word se pasan como variables de entorno a la ejecución de sh .
  • sh ejecuta el contenido de la cadena que se pasa.
  • Las cadenas escritas una junto a otra se convierten en una cadena, esa cadena es:
    • ' echo " ' + " $ (cat template.txt) " + ' " '
  • Dado que la sustitución es entre " , " $ (cat template.txt) " se convierte en la salida de cat template.txt .
  • Por lo tanto, el comando ejecutado por sh -c se convierte en:
    • echo " El número es $ {i} \ nLa palabra es $ {word} " ,
    • donde i y word son las variables de entorno especificadas.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top