Comment remplacer ${} emplacements dans un fichier texte?

je veux Piper la sortie d'un fichier" template "dans MySQL, le fichier ayant des variables comme ${dbName} intercalé. Quel est l'utilitaire en ligne de commande pour remplacer ces instances et transférer la sortie à la sortie standard?

103
demandé sur Yves M. 2009-01-06 10:00:16

14 réponses

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 la pointe de passer multiples -e arguments à la même sed invocation.

128
répondu user 2016-01-07 13:49:01

mise à Jour

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

i=32 word=foo envsubst < template.txt

bien sûr, si je et mot sont dans votre environnement, alors il est juste

envsubst < template.txt

sur mon Mac on dirait qu'il a été installé dans le cadre de gettext et de MacGPG2

Vieille Réponse

Voici une amélioration à la solution de mogsie sur une question similaire,ma solution ne vous oblige pas à escale double guillemets, mogsie's fait, mais son est un liner!

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

la puissance sur ces deux solutions est que vous obtenez seulement quelques types d'extensions shell qui ne se produisent pas normalement $(...)),"...`, et $(...), bien que backslash soit un caractère d'évasion ici, mais vous n'avez pas à vous inquiéter que l'analyse a un bug, et il fait plusieurs lignes très bien.

113
répondu plockc 2017-05-23 12:34:53

utiliser /bin/sh . Créez un petit script shell qui définit les variables, puis analysez le modèle en utilisant le shell lui-même. Comme ceci (éditer pour gérer les nouvelles lignes correctement):

modèle de fichier.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
40
répondu gnud 2012-10-27 07:25:10

je repensais à cela, compte tenu de l'intérêt récent, et je pense que l'outil auquel je pensais à l'origine était m4 , le macro processeur pour autotools. Ainsi, au lieu de la variable que j'ai spécifiée à l'origine, vous utiliseriez:

$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
17
répondu Dana the Sane 2011-05-19 15:19:00
Modèle

.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=
declare file_input=
declare file_output=

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

. /parser.sh data.sh modèle.txt parsed_file.txt

parsed_file.txt

Variable 1 value: value 1
Variable 2 value: value 2
12
répondu ChaPuZ 2009-08-20 21:31:19

voici ma solution avec perl basée sur l'ancienne réponse, remplace les variables d'environnement:

perl -p -e 's/$\{(\w+)\}/(exists $ENV{}?$ENV{}:"missing variable ")/eg' < infile > outfile
9
répondu Thomas 2013-06-06 15:32:34

voici un fonction de Bash robuste qui-malgré l'utilisation de eval - devrait être sûr à utiliser.

toutes les variables ${varName} les références dans le texte d'entrée sont étendues sur la base des variables du shell appelant.

Rien d'autre est élargi: ni les références à des variables dont les noms sont pas entre {...} (comme $varName ), ni de commande substitutions ( $(...) et syntaxe héritée `...` ), ni substitutions arithmétiques ( $((...)) et syntaxe héritée $[...] ).

pour traiter un $ comme un littéral, \ - s'en échapper; p.ex.: ${HOME}

noter 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)

fonction source code:

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 '`([$' '')
    # ... then selectively reenable ${ references
    lineEscaped=${lineEscaped//$''{/${}
    # Finally, escape embedded double quotes to preserve them.
    lineEscaped=${lineEscaped//\"/\\"}
    eval "printf '%s\n' \"$lineEscaped\"" | tr '' '`([$'
  done
}

la fonction suppose qu'aucun 0x1 , 0x2 , 0x3 , et 0x4 caractères de contrôle sont présents dans l'entrée, parce que ces caractères. sont utilisés à l'interne - depuis la fonction traite texte , qui devrait être une hypothèse sûre.

7
répondu mklement0 2016-10-21 03:43:14

si vous êtes ouvert à l'utilisation de Perl , ce serait ma suggestion. Bien qu'il y ait probablement quelques sed et/ou AWK experts qui savent probablement comment faire beaucoup plus facile. Si vous avez un mapping plus complexe avec plus que juste dbName pour vos remplacements vous pourriez étendre cela assez facilement, mais vous pourriez tout aussi bien le mettre dans un script Perl standard à ce point.

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

A script Perl court pour faire quelque chose un peu plus compliqué (gérer plusieurs touches):

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

si vous nommez le script ci-dessus comme remplacer-script, il pourrait alors être utilisé comme suit:

replace-script < yourfile | mysql
6
répondu Beau Simensen 2012-10-27 07:21:24

créer rendertemplate.sh :

#!/usr/bin/env bash

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

et template.tmpl :

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

Rendre le modèle:

$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl 
Hello, Foo
Goodbye, Bar
5
répondu neu242 2017-02-22 09:01:44
"151920920 de 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 < 
}

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

template file.tpl > result.txt
4
répondu user976433 2011-10-03 10:08:31

je suggère 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.

alors vous pouvez faire une simple doublure comme la suivante:

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

C'est beaucoup plus sûr que eval et plus facile alors en utilisant regex ou sed

3
répondu spudfkc 2016-02-23 20:44:52

j'ai trouvé ce fil en me demandant la même chose. Il m'a inspiré à cela (attention avec les bâtons arrière)

$ echo $MYTEST
pass!
$ cat FILE
hello $MYTEST world
$ eval echo `cat FILE`
hello pass! world
2
répondu GlueC 2011-05-16 12:58:01

beaucoup de choix ici, mais j'ai pensé jeter le mien sur le tas. Il est basé sur perl, ne cible que les variables de la forme $ {...}, prend le fichier à traiter comme un argument et affiche le fichier converti sur stdout:

use Env;
Env::import();

while(<>) { $_ =~ s/(${\w+})//eeg; $text .= $_; }

print "$text";

bien sûr, je ne suis pas vraiment une personne perl, donc il pourrait facilement y avoir un défaut fatal (fonctionne pour moi cependant).

2
répondu sfitts 2014-07-12 01:55:27

il peut être fait en bash lui-même si vous avez le contrôle du format de fichier de configuration. Vous avez juste besoin de source (".") le fichier de configuration plutôt que de le sous-titrer. Cela garantit que les variables sont créées dans le contexte du shell courant (et continuent d'exister) plutôt que dans le sous-puits (où la variable disparaît lorsque le sous-puits sort).

$ 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 d'exécuter ainsi (le la compilation dépend de votre format de saisie).

$ 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 '^$'
        | 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 particulier, vous pourriez 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

puis pipe la sortie de go.bash en MySQL et voila, j'espère que vous ne sera pas détruire votre base de données :-).

1
répondu paxdiablo 2015-08-06 12:15:06