Question

Je souhaite diriger la sortie d'un " modèle " fichier dans MySQL, le fichier ayant des variables telles que $ {nom_base} intercalé. Quel est l'utilitaire de ligne de commande pour remplacer ces instances et vider la sortie vers la sortie standard?

Était-ce utile?

La solution

Sed !

Modèle donné.txt:

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

il suffit de dire:

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

Merci à Jonathan Leffler pour le conseil de passer plusieurs arguments -e à la même invocation sed .

Autres conseils

Mettre à jour

Voici une solution de yottatsa sur une question similaire qui ne remplace que des variables telles que $ VAR ou $ {VAR }, et est un bref one-liner

i=32 word=foo envsubst < template.txt

Bien sûr, si i et mot se trouvent dans votre environnement, il s'agit simplement de

envsubst < template.txt

Sur mon Mac, il semble que le logiciel ait été installé dans le cadre de gettext et de MacGPG2

.

Ancienne réponse

Voici une amélioration de la solution de mogsie sur une question similaire, ma solution ne vous oblige pas à écarter les droits citations, Mogsie est fait, mais son est un one liner!

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

Le pouvoir de ces deux solutions réside dans le fait que vous n’obtenez que quelques types d’extensions de shell qui ne se produisent pas normalement $ ((...)), `...` et $ (...), bien que la barre oblique inverse est un caractère d'échappement ici, mais vous n'avez pas à vous inquiéter du fait que l'analyse présente un bogue, et cela résout parfaitement plusieurs lignes.

Utilisez / bin / sh . Créez un petit script shell qui définit les variables, puis analysez le modèle à l'aide du shell lui-même. Comme si (modifier pour gérer correctement les nouvelles lignes):

Fichier template.txt:

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

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

Sortie:

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

J'y pensais encore, compte tenu de l'intérêt récent, et je pense que l'outil auquel je pensais à l'origine était m4 , le processeur de macros pour les outils automatiques. Donc, au lieu de la variable que j'ai spécifiée à l'origine, vous utiliseriez:

$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 fichier_parse.txt

fichier_parsé.txt

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

voici ma solution avec perl basée sur la réponse précédente, remplace les variables d'environnement:

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

Voici une fonction Bash robuste qui, malgré l'utilisation de eval - devrait être utilisée en toute sécurité.

Toutes les références de variable $ {varName} dans le texte d'entrée sont développées en fonction des variables du shell appelant.

Rien d’autre n’est développé: aucune des références de variable dont le nom n’est pas ne figure entre {...} (comme $ varName ), ni les substitutions de commandes ( $ (...) et la syntaxe héritée `...` ), ni les substitutions arithmétiques ( $ ( (...)) et la syntaxe classique $ [...] ).

Pour traiter un $ comme un littéral, \ -escape it; Exemple: \ $ {HOME}

Notez que l'entrée n'est acceptée que via stdin .

Exemple:

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

Code source de la fonction:

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 fonction suppose qu’aucun 0x1 , 0x2 , 0x3 et 0x4 ne sont des caractères de contrôle présent dans l'entrée, parce que ces caractères. sont utilisés en interne - puisque la fonction traite text , cela devrait être une hypothèse sûre.

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

La fonction suppose qu’aucun 0x1 , 0x2 , 0x3 et 0x4 ne sont des caractères de contrôle présent dans l'entrée, parce que ces caractères. sont utilisés en interne - puisque la fonction traite text , cela devrait être une hypothèse sûre.

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

La fonction suppose qu’aucun 0x1 , 0x2 , 0x3 et 0x4 ne sont des caractères de contrôle présent dans l'entrée, parce que ces caractères. sont utilisés en interne - puisque la fonction traite text , cela devrait être une hypothèse sûre.

done }

La fonction suppose qu’aucun 0x1 , 0x2 , 0x3 et 0x4 ne sont des caractères de contrôle présent dans l'entrée, parce que ces caractères. sont utilisés en interne - puisque la fonction traite text , cela devrait être une hypothèse sûre.

Si vous êtes disposé à utiliser Perl , ce serait ma suggestion. Bien qu'il existe probablement des sed et / ou AWK experts qui savent probablement comment faire cela beaucoup plus facilement. Si vous avez un mappage plus complexe avec plus que simplement dbName pour vos remplacements, vous pouvez l’étendre assez facilement, mais vous pouvez tout aussi bien le mettre dans un script Perl standard à ce stade.

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

Un court script Perl pour faire quelque chose de légèrement plus compliqué (gérer plusieurs clés):

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

Si vous êtes disposé à utiliser Perl , ce serait ma suggestion. Bien qu'il existe probablement des sed et / ou AWK experts qui savent probablement comment faire cela beaucoup plus facilement. Si vous avez un mappage plus complexe avec plus que simplement dbName pour vos remplacements, vous pouvez l’étendre assez facilement, mais vous pouvez tout aussi bien le mettre dans un script Perl standard à ce stade.

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

Un court script Perl pour faire quelque chose de légèrement plus compliqué (gérer plusieurs clés):

replace-script < yourfile | mysql

Si vous appelez le script ci-dessus comme script de remplacement, vous pouvez l'utiliser comme suit:

<*>\}/$replace{

Si vous êtes disposé à utiliser Perl , ce serait ma suggestion. Bien qu'il existe probablement des sed et / ou AWK experts qui savent probablement comment faire cela beaucoup plus facilement. Si vous avez un mappage plus complexe avec plus que simplement dbName pour vos remplacements, vous pouvez l’étendre assez facilement, mais vous pouvez tout aussi bien le mettre dans un script Perl standard à ce stade.

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

Un court script Perl pour faire quelque chose de légèrement plus compliqué (gérer plusieurs clés):

<*>

Si vous appelez le script ci-dessus comme script de remplacement, vous pouvez l'utiliser comme suit:

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

Si vous appelez le script ci-dessus comme script de remplacement, vous pouvez l'utiliser comme suit:

<*>

Créer rendertemplate.sh :

#!/usr/bin/env bash

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

Et template.tmpl :

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

Rendez le modèle:

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

fichier.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

Je suggérerais d'utiliser quelque chose comme Sigil :      https://github.com/gliderlabs/sigil

Il est compilé en un seul binaire, il est donc extrêmement facile à installer sur les systèmes.

Ensuite, vous pouvez faire une simple ligne comme suit:

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

Cela est beaucoup plus sûr que eval et plus facile que d'utiliser regex ou sed

J'ai trouvé ce fil en me demandant la même chose. Cela m’inspire à cela (attention aux backticks)

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

Beaucoup de choix ici, mais je pensais que jetterais le mien sur le tas. Il est basé sur Perl. Seules les variables cibles de la forme $ {...} prennent le fichier à traiter en tant qu’argument et sortent le fichier converti sur stdout:

use Env;
Env::import();

while(<>) { 

Beaucoup de choix ici, mais je pensais que jetterais le mien sur le tas. Il est basé sur Perl. Seules les variables cibles de la forme $ {...} prennent le fichier à traiter en tant qu’argument et sortent le fichier converti sur stdout:

<*>

Bien sûr, je ne suis pas vraiment un Perl, il pourrait donc y avoir un défaut fatal (cela fonctionne pour moi cependant).

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

Beaucoup de choix ici, mais je pensais que jetterais le mien sur le tas. Il est basé sur Perl. Seules les variables cibles de la forme $ {...} prennent le fichier à traiter en tant qu’argument et sortent le fichier converti sur stdout:

<*>

Bien sûr, je ne suis pas vraiment un Perl, il pourrait donc y avoir un défaut fatal (cela fonctionne pour moi cependant).

; } print "$text";

Bien sûr, je ne suis pas vraiment un Perl, il pourrait donc y avoir un défaut fatal (cela fonctionne pour moi cependant).

Cela peut être fait dans bash lui-même si vous avez le contrôle du format du fichier de configuration. Il vous suffit de source (".") Le fichier de configuration plutôt que de le sous-shell. Cela garantit que les variables sont créées dans le contexte du shell actuel (et continuent d'exister) plutôt que dans le sous-shell (où la variable disparaît à la fermeture du sous-shell).

$ 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 votre fichier de configuration ne peut pas être un script shell, vous pouvez simplement le "compiler" avant de l'exécuter ainsi (la compilation dépend de votre format d'entrée).

$ 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 '^

Dans votre cas spécifique, vous pouvez utiliser quelque chose comme:

$ 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

Ensuite, dirigez la sortie de go.bash vers MySQL et le tour est joué, espérons que vous ne détruisez pas votre base de données: -).

| 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

Dans votre cas spécifique, vous pouvez utiliser quelque chose comme:

<*>

Ensuite, dirigez la sortie de go.bash vers MySQL et le tour est joué, espérons que vous ne détruisez pas votre base de données: -).

Voici un moyen de demander au shell d'effectuer la substitution à votre place, comme si le contenu du fichier était saisi à la place entre guillemets.

Utilisation de l'exemple de template.txt avec le contenu:

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

La ligne suivante obligera le shell à interpoler le contenu de template.txt et à écrire le résultat dans la sortie standard.

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

Explication:

  • i et le mot sont passés en tant que variables d'environnement tronquées à l'exécution de sh .
  • sh exécute le contenu de la chaîne à laquelle il est transmis.
  • Les chaînes écrites les unes à côté des autres deviennent une chaîne, cette chaîne est:
    • ' echo "' +" $ (cat template.txt) " + ' " '
  • Étant donné que la substitution est entre " , " $ (cat template.txt) " devient la sortie de cat template.txt .
  • Ainsi, la commande exécutée par sh -c devient:
    • echo "Le nombre est $ {i} \ nLe mot est $ {mot}" ,
    • i et mot sont les variables d'environnement spécifiées.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top