Je veux attribuer dynamiquement des valeurs aux variables en utilisant eval
. L'exemple factice suivant fonctionne:
var_name="fruit"
var_value="orange"
eval $(echo $var_name=$var_value)
echo $fruit
orange
Cependant, lorsque la valeur de la variable contient des espaces, eval
renvoie une erreur, même si elle $var_value
est placée entre guillemets doubles:
var_name="fruit"
var_value="blue orange"
eval $(echo $var_name="$var_value")
bash: orange : command not found
Une façon de contourner cela?
eval
cette façon est faux. Vous développez$var_value
avant de le transmettre, ceeval
qui signifie qu'il va être interprété comme du code shell! (essayez par exemple avecvar_value="';:(){ :|:&};:'"
)eval
(c'est une des raisons pour lesquelles j'ai dit que vous ne devriez pas utilisereval
).$var_value
est celui de l'inversion des guillemets - en supposant une valeur sûre pour$var_name
(ce qui peut être une hypothèse tout aussi dangereuse, en fait) , alors vous devriez inclure les guillemets doubles du côté droit entre guillemets simples - pas vice versa.eval
, en utilisantprintf
et son formatbash
spécifique%q
. Ce n'est toujours pas une recommandation à utilisereval
, mais je pense que c'est plus sûr qu'auparavant. Le fait que vous ayez à faire autant d'efforts pour le faire fonctionner est la preuve que vous devez utiliserdeclare
ou nommer des références à la place.set -- a bunch of args; eval "process2 $(process1 "$@")"
oùprocess1
imprime simplement les nombres cités comme"${1}" "${8}" "${138}"
. C'est fou simple - et aussi facile que'"${'$((i=$i+1))'}" '
dans la plupart des cas. les références indexées le rendent sûr, robuste et rapide . Pourtant - j'ai voté positivement.Un bon moyen de travailler avec
eval
est de le remplacer parecho
pour les tests.echo
eteval
travailler de la même manière (si nous mettons de côté l'\x
expansion effectuée par certainesecho
implémentations comme cellebash
de certaines dans certaines conditions).Les deux commandes joignent leurs arguments avec un espace entre les deux. La différence est que le résultat est
echo
affiché pendant qu'ileval
évalue / interprète le code shell comme résultat.Donc, pour voir quel code shell
évaluerait, vous pouvez exécuter:
Ce n'est pas ce que vous voulez, ce que vous voulez c'est:
De plus, l'utilisation
$(echo ...)
ici n'a pas de sens.Pour afficher ce qui précède, vous devez exécuter:
Donc, pour l'interpréter, c'est simplement:
Notez qu'il peut également être utilisé pour définir des éléments de tableau individuels:
Comme d'autres l'ont dit, si vous ne vous souciez pas que votre code soit
bash
spécifique, vous pouvez l'utiliserdeclare
comme:Notez cependant qu'il a des effets secondaires.
Il limite la portée de la variable à la fonction dans laquelle elle est exécutée. Vous ne pouvez donc pas l'utiliser par exemple dans des choses comme:
Parce que cela déclarerait une
foo
variable locale àsetvar
so serait inutile.bash-4.2
ajouté une-g
option pourdeclare
déclarer une variable globale , mais ce n'est pas ce que nous voulons non plus car notresetvar
définirait une variable globale par opposition à celle de l'appelant si l'appelant était une fonction, comme dans:qui produirait:
Notez également que while
declare
est appelédeclare
(en faitbash
emprunté au concept du shell Korntypeset
), si la variable est déjà définie,declare
ne déclare pas de nouvelle variable et la façon dont l'affectation est effectuée dépend du type de la variable.Par exemple:
produira un résultat différent (et aura potentiellement des effets secondaires désagréables) s'il a
varname
été précédemment déclaré comme un scalaire , un tableau ou un tableau associatif .la source
bash
n'est pas disponible (ou lorsque vous réalisez que vous avez besoin d'un shell meilleur / plus rapide). Laeval
syntaxe fonctionne dans tous les shells de type Bourne et est POSIX donc tous les systèmes auront unsh
où cela fonctionne. (cela signifie également que ma réponse s'applique à tous les obus, et tôt ou tard, comme cela arrive souvent ici, vous verrez une question spécifique non-bash fermée en double de celle-ci.$var_name
contient des jetons? ... comme;
?eval
etdeclare
(pensezPATH
,TMOUT
,PS4
,SECONDS
...).export
. je ne suis pas le parenthèse à la fin cependant.Si tu fais:
... et
$name
contient un;
- ou l'un de plusieurs autres jetons que le shell pourrait interpréter comme délimitant une commande simple - précédé d'une syntaxe de shell appropriée, qui sera exécutée.PRODUCTION
Cependant, il peut parfois être possible de séparer l'évaluation et l'exécution de ces déclarations. Par exemple,
alias
peut être utilisé pour pré-évaluer une commande. Dans l'exemple suivant, la définition de variable est enregistrée dans un fichieralias
qui ne peut être déclaré avec succès que si la$nm
variable qu'il évalue ne contient aucun octet qui ne correspond pas aux caractères alphanumériques ASCII ou_
.eval
est utilisé ici pour gérer l'appel du nouveau àalias
partir d'un nom de variable. Mais il n'est appelé du tout que si laalias
définition précédente réussit, et bien que je sache que de nombreuses implémentations différentes accepteront de nombreux types de valeurs différents pour lesalias
noms, je n'en ai pas encore rencontré une qui acceptera une complètement vide. .La définition dans le
alias
est pour_$nm
, cependant, et ceci pour garantir qu'aucune valeur d'environnement significative n'est écrasée. Je ne connais aucune valeur d'environnement notable commençant par un_
et c'est généralement une valeur sûre pour une déclaration semi-privée.Quoi qu'il en soit, si la
alias
définition réussit, elle déclarera une valeuralias
nommée pour$nm
. Eteval
n'appellera quealias
si if ne commence pas non plus par un nombre - elseeval
ne reçoit qu'un argument nul. Par conséquent, si les deux conditions sont remplies,eval
l'alias et la définition de variable enregistrée dans l'alias sont créés, après quoi la nouvellealias
est rapidement supprimée de la table de hachage.la source
;
n'est pas autorisé dans les noms de variables. Si vous ne contrôlez pas le contenu de$name
, vous devez également le nettoyer pourexport
/declare
. Bien qu'ilexport
n'exécute pas de code, la définition de certaines variables commePATH
,PS4
et beaucoup de celles-ciinfo -f bash -n 'Bash Variables'
ont des effets secondaires tout aussi dangereux.eval
la première passe - c'est une extension variable. Comme vous l'avez dit ailleurs, dans ce contexte, c'est tout à fait permis. L'argument $ PATH est toujours très bon - j'ai fait une petite modification et j'en ajouterai plus tard.zsh
,pdksh
,mksh
,yash
ne se plaignent pasunset 'a;b'
.unset -v -- ...
aussi.