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?
14 réponses
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.
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
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"
.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
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
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.
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
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
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
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
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
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).
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 :-).