J'essaie de trouver comment faire en sorte que bash (force?) Développe les variables dans une chaîne (qui a été chargée à partir d'un fichier).
J'ai un fichier appelé "something.txt" avec le contenu:
hello $FOO world
Je cours alors
export FOO=42
echo $(cat something.txt)
cela renvoie:
hello $FOO world
Il n'a pas développé $ FOO même si la variable a été définie. Je ne peux pas évaluer ou générer le fichier - car il essaiera de l'exécuter (il n'est pas exécutable tel quel - je veux juste la chaîne avec les variables interpolées).
Des idées?
eval
.eval
et il est important d'être conscient des implications.Réponses:
Je suis tombé sur ce que je pense être LA réponse à cette question: la
envsubst
commande.Si ce n'est pas déjà disponible dans votre distribution, c'est dans le
Paquet GNU
gettext
.@Rockallite - J'ai écrit un petit script wrapper pour résoudre le problème '\ $'.
(BTW, il existe une "fonctionnalité" d'envsubst, expliquée à https://unix.stackexchange.com/a/294400/7088 pour développer uniquement certaines des variables de l'entrée, mais je conviens qu'échapper aux exceptions est beaucoup plus pratique.)
Voici mon script:
#! /bin/bash ## -*-Shell-Script-*- CmdName=${0##*/} Usage="usage: $CmdName runs envsubst, but allows '\$' to keep variables from being expanded. With option -sl '\$' keeps the back-slash. Default is to replace '\$' with '$' " if [[ $1 = -h ]] ;then echo -e >&2 "$Usage" ; exit 1 ;fi if [[ $1 = -sl ]] ;then sl='\' ; shift ;fi sed 's/\\\$/\${EnVsUbDolR}/g' | EnVsUbDolR=$sl\$ envsubst "$@"
la source
$
échappement du signe dollar ( ), par exemple,echo '\$USER' | envsubst
il affichera le nom d'utilisateur actuel avec une barre oblique inversée, non$USER
.brew link --force gettext
De nombreuses réponses utilisant
eval
etecho
type de travail, mais interrompent sur diverses choses, telles que plusieurs lignes, la tentative d'échapper aux méta-caractères du shell, les échappements à l'intérieur du modèle qui ne sont pas destinés à être développés par bash, etc.J'ai eu le même problème et j'ai écrit cette fonction shell qui, pour autant que je sache, gère tout correctement. Cela supprimera toujours uniquement les nouvelles lignes de fin du modèle, à cause des règles de substitution de commande de bash, mais je n'ai jamais trouvé que cela posait problème tant que tout le reste reste intact.
apply_shell_expansion() { declare file="$1" declare data=$(< "$file") declare delimiter="__apply_shell_expansion_delimiter__" declare command="cat <<$delimiter"$'\n'"$data"$'\n'"$delimiter" eval "$command" }
Par exemple, vous pouvez l'utiliser comme ceci avec un
parameters.cfg
qui est en fait un script shell qui ne fait que définir des variables, et untemplate.txt
qui est un modèle qui utilise ces variables:. parameters.cfg printf "%s\n" "$(apply_shell_expansion template.txt)" > result.txt
En pratique, je l'utilise comme une sorte de système de gabarit léger.
la source
eval
pièges habituels . Essayez d'ajouter; $(eval date)
à la fin de n'importe quelle ligne dans le fichier d'entrée et il exécutera ladate
commande.tu peux essayer
echo $(eval echo $(cat something.txt))
la source
echo -e "$(eval "echo -e \"`<something.txt`\"")"
si vous avez besoin de conserver de nouvelles lignes.template.txt
texte est. Cette opération est dangereuse car elle exécute (évalue) les commandes si elles le sont.Vous ne voulez pas imprimer chaque ligne, vous voulez l' évaluer pour que Bash puisse effectuer des substitutions de variables.
FOO=42 while read; do eval echo "$REPLY" done < something.txt
Voir
help eval
ou le manuel Bash pour plus d'informations.la source
eval
est dangereux ; vous obtenez non seulement$varname
élargi (comme vous le feriez avecenvsubst
), mais$(rm -rf ~)
aussi.Une autre approche (qui semble dégoûtante, mais je la mets quand même ici):
Écrivez le contenu de quelque chose.txt dans un fichier temporaire, avec une instruction echo entourée:
something=$(cat something.txt) echo "echo \"" > temp.out echo "$something" >> temp.out echo "\"" >> temp.out
puis retournez-le dans une variable:
RESULT=$(source temp.out)
et le $ RESULT aura tout développé. Mais cela semble tellement faux!
la source
Si vous voulez seulement que les références de variables soient développées (un objectif que j'avais pour moi), vous pouvez faire ce qui suit.
contents="$(cat something.txt)" echo $(eval echo \"$contents\")
(Les guillemets échappés autour de $ contents sont la clé ici)
la source
eval "echo \"$$contents\""
et elle a conservé l'espace blancSolution suivante:
permet de remplacer les variables qui sont définies
laisse les espaces réservés de variables inchangés qui ne sont pas définis. Ceci est particulièrement utile lors des déploiements automatisés.
prend en charge le remplacement des variables dans les formats suivants:
${var_NAME}
$var_NAME
signale quelles variables ne sont pas définies dans l'environnement et renvoie le code d'erreur pour de tels cas
TARGET_FILE=someFile.txt; ERR_CNT=0; for VARNAME in $(grep -P -o -e '\$[\{]?(\w+)*[\}]?' ${TARGET_FILE} | sort -u); do VAR_VALUE=${!VARNAME}; VARNAME2=$(echo $VARNAME| sed -e 's|^\${||g' -e 's|}$||g' -e 's|^\$||g' ); VAR_VALUE2=${!VARNAME2}; if [ "xxx" = "xxx$VAR_VALUE2" ]; then echo "$VARNAME is undefined "; ERR_CNT=$((ERR_CNT+1)); else echo "replacing $VARNAME with $VAR_VALUE2" ; sed -i "s|$VARNAME|$VAR_VALUE2|g" ${TARGET_FILE}; fi done if [ ${ERR_CNT} -gt 0 ]; then echo "Found $ERR_CNT undefined environment variables"; exit 1 fi
la source
Si something.txt a seulement une ligne, une
bash
méthode, (une version plus courte de Michael Neale réponse « dégueu » ), en utilisant processus et substitution de commande :FOO=42 . <(echo -e echo $(<something.txt))
Production:
Notez que ce
export
n'est pas nécessaire.Si quelque chose.txt a une ou plusieurs lignes, une méthode de valorisation GNU :
sed
e
FOO=42 sed 's/"/\\\"/g;s/.*/echo "&"/e' something.txt
la source
sed
évaluation correspondait le mieux à mon objectif. J'avais besoin de produire des scripts à partir de modèles, qui auraient des valeurs remplies à partir de variables exportées dans un autre fichier de configuration. Il gère correctement les échappements pour l'expansion de la commande, par exemple, placez\$(date)
le modèle pour obtenir$(date)
la sortie. Merci!$ eval echo $(cat something.txt) hello 42 world $ bash --version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17) Copyright (C) 2007 Free Software Foundation, Inc.
la source
foo=45 file=something.txt # in a file is written: Hello $foo world! eval echo $(cat $file)
la source
envsubst
est une excellente solution (voir la réponse de LenW) si le contenu que vous remplacez est de longueur "raisonnable".Dans mon cas, j'avais besoin de remplacer le contenu d'un fichier pour remplacer le nom de la variable.
envsubst
exige que le contenu soit exporté en tant que variables d'environnement et bash a un problème lors de l'exportation de variables d'environnement de plus d'un mégaoctet.solution awk
Utilisation de la solution de cuonglm à partir d'une question différente:
needle="doc1_base64" # The "variable name" in the file. (A $ is not needed.) needle_file="doc1_base64.txt" # Will be substituted for the needle haystack=$requestfile1 # File containing the needle out=$requestfile2 awk "BEGIN{getline l < \"${needle_file}\"}/${needle}/{gsub(\"${needle}\",l)}1" $haystack > $out
Cette solution fonctionne même pour les fichiers volumineux.
la source
Les travaux suivants:
bash -c "echo \"$(cat something.txt)"\"
la source
$foo
, mais des extensions non sûres comme$(rm -rf ~)
.