Considérez cet extrait:
$ SOMEVAR=AAA
$ echo zzz $SOMEVAR zzz
zzz AAA zzz
Ici , je me suis fixé $SOMEVAR
à AAA
la première ligne - et quand je fais l' écho sur la deuxième ligne, je reçois le AAA
contenu comme prévu.
Mais alors, si j'essaie de spécifier la variable sur la même ligne de commande que le echo
:
$ SOMEVAR=BBB echo zzz $SOMEVAR zzz
zzz AAA zzz
... Je n'obtiens pas BBB
comme prévu - j'obtiens l'ancienne valeur ( AAA
).
Est-ce que c'est ainsi que les choses sont censées être? Si tel est le cas, comment se fait-il que vous puissiez spécifier des variables comme LD_PRELOAD=/... program args ...
et que cela fonctionne? Qu'est-ce que je rate?
LD_PRELOAD
fonctionne est que la variable est définie dans l' environnement du programme - pas sur sa ligne de commande.Réponses:
Ce que vous voyez est le comportement attendu. Le problème est que le shell parent évalue
$SOMEVAR
sur la ligne de commande avant d'appeler la commande avec l'environnement modifié. Vous devez obtenir l'évaluation de$SOMEVAR
différé jusqu'à ce que l'environnement soit défini.Vos options immédiates comprennent:
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz
.SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'
.Les deux utilisent des guillemets simples pour empêcher le shell parent d'évaluer
$SOMEVAR
; il n'est évalué qu'après avoir été défini dans l'environnement (temporairement, pour la durée de la commande unique).Une autre option consiste à utiliser la notation sous-shell (comme l'a également suggéré Marcus Kuhn dans sa réponse ):
La variable est définie uniquement dans le sous-shell
la source
Le problème, revisité
Franchement, le manuel est déroutant sur ce point. Le manuel GNU Bash dit:
Si vous analysez vraiment la phrase, ce qu'elle dit, c'est que l' environnement de la commande / fonction est modifié, mais pas l'environnement du processus parent. Donc, cela fonctionnera:
car l'environnement de la commande env a été modifié avant son exécution. Cependant, cela ne fonctionnera pas:
à cause du moment où l'expansion des paramètres est effectuée par le shell.
Étapes de l'interprète
Une autre partie du problème est que Bash définit ces étapes pour son interpréteur:
Ce qui se passe ici, c'est que les fonctions intégrées n'ont pas leur propre environnement d'exécution, donc elles ne voient jamais l'environnement modifié. En outre, les commandes simples (par exemple / bin / echo) n'obtenir un ennvironment modifié ( ce qui explique pourquoi l'exemple env a travaillé) mais l'expansion de la coquille se déroule dans le courant environnement à l' étape 4.
En d'autres termes, vous ne passez pas 'aaa $ TESTVAR ccc' à / bin / echo; vous passez la chaîne interpolée (telle que développée dans l'environnement actuel) à / bin / echo. Dans ce cas, puisque l'environnement actuel n'a pas de TESTVAR , vous passez simplement «aaa ccc» à la commande.
Résumé
La documentation pourrait être beaucoup plus claire. Heureusement qu'il y a Stack Overflow!
Voir également
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
la source
FOO=foo eval 'echo $FOO'
imprimefoo
comme prévu. Cela signifie que vous pouvez faire des choses commeIFS="..." read ...
.Pour réaliser ce que vous voulez, utilisez
Raison:
Vous devez séparer l'affectation par un point-virgule ou une nouvelle ligne de la commande suivante, sinon elle n'est pas exécutée avant le développement des paramètres pour la commande suivante (écho).
Vous devez effectuer l'affectation dans un environnement de sous - shell , pour vous assurer qu'elle ne persiste pas au-delà de la ligne actuelle.
Cette solution est plus courte, plus propre et plus efficace que certaines des autres suggérées, en particulier elle ne crée pas de nouveau procédé.
la source
(export SOMEVAR=BBB; python -c "from os import getenv; print getenv('SOMEVAR')")
SOMEVAR=BBB python -c "from os import getenv; print getenv('SOMEVAR')"
La raison en est que cela définit une variable d'environnement pour une ligne. Mais,
echo
ne fait pas l'expansion,bash
fait. Par conséquent, votre variable est en fait développée avant que la commande ne soit exécutée, même si elleSOME_VAR
estBBB
dans le contexte de la commande echo.Pour voir l'effet, vous pouvez faire quelque chose comme:
Ici, la variable n'est pas développée tant que le processus enfant n'est pas exécuté, vous voyez donc la valeur mise à jour. si vous vérifiez à
SOME_VARIABLE
nouveau dans le shell parent, c'est toujoursAAA
, comme prévu.la source
Utiliser un ; pour séparer les instructions qui sont sur la même ligne.
la source
LD_PRELOAD
et tel peut fonctionner devant un exécutable sans point-virgule, cependant ... Merci encore une fois - bravo!Voici une alternative:
la source
&&
ou;
sépariez les commandes, l'affectation persiste, ce qui n'est pas le comportement souhaité par OP. Markus Kuhn a la version correcte de cette réponse.