web-dev-qa-db-fra.com

Comment définir une variable d'environnement sur la ligne de commande et la faire apparaître dans les commandes?

Si je cours

export TEST=foo
echo $TEST

Il produit foo.

Si je cours

TEST=foo echo $TEST

Ce ne est pas. Comment puis-je obtenir cette fonctionnalité sans utiliser l'exportation ou un script?

175
ashleysmithgpu

C'est parce que le Shell développe la variable dans la ligne de commande avant il exécute réellement la commande et à ce moment la variable n'existe pas. Si tu utilises

TEST=foo; echo $TEST

ça va marcher.

export fera apparaître la variable dans l'environnement des commandes exécutées ultérieurement (pour savoir comment cela fonctionne en bash, voir help export). Si vous avez seulement besoin que la variable apparaisse dans l'environnement d'une commande, utilisez ce que vous avez essayé, à savoir:

TEST=foo your-application
209
peterph

Je soupçonne que vous voulez avoir des variables Shell pour avoir une portée limitée, plutôt que des variables d'environnement. Les variables d'environnement sont une liste de chaînes passées aux commandes lorsqu'elles sont exécutées.

Dans

var=value echo whatever

Vous passez le var=value chaîne vers l'environnement reçu par l'écho. Cependant, echo ne fait rien avec sa liste d'environnement¹ et de toute façon dans la plupart des shells, echo est intégré et donc pas exécuté .

Si vous aviez écrit

var=value sh -c 'echo "$var"'

Cela aurait été une autre affaire. Ici, on passe var=value à la commande sh, et sh utilise son environnement. Les shells convertissent chacune des variables qu'ils reçoivent de leur environnement en une variable Shell, donc la variable d'environnement varsh reçoit sera convertie en $var variable, et lorsqu'elle l'étend dans cette ligne de commande echo, elle devient echo value. Étant donné que l'environnement est hérité par défaut, echo recevra également var=value dans son environnement (ou le ferait s'il était exécuté), mais encore une fois, echo ne se soucie pas de l'environnement.

Maintenant, si comme je le soupçonne, ce que vous voulez, c'est limiter la portée des variables Shell, il existe plusieurs approches possibles.

Portable (Bourne et POSIX):

(var=value; echo "1: $var"); echo "2: $var"

Le (...) ci-dessus démarre un sous-shell (un nouveau processus Shell dans la plupart des shells), donc toute variable déclarée ici n'affectera que ce sous-shell, donc je m'attendrais à ce que le code ci-dessus produise "1: valeur" et "2:" ou "2: quelle que soit-var-was-set-to-before".

Avec la plupart des shells de type Bourne, vous pouvez utiliser des fonctions et le builtin "local":

f() {
  local var
  var=value
  echo "1: $var"
}
f
echo "2: $var"

Avec zsh, vous pouvez utiliser des fonctions en ligne:

(){ local var=value; echo "1: $var"; }; echo "2: $var"

ou:

function { local var=value; echo "1: $var"; }; echo "2: $var"

Avec bash et zsh (mais pas ash, pdksh ou AT&T ksh), cette astuce fonctionne également:

var=value eval 'echo "1: $var"'; echo "2: $var"

Une variante qui fonctionne dans quelques autres shells (dash, mksh, yash) mais pas zsh (sauf dans sh/ksh émulation):

var=value command eval 'echo "1: $var"'; echo "2: $var"

(l'utilisation de command devant un module spécial spécial (ici eval) dans les shells POSIX supprime leur particularité (ici, les affectations de variables à partir d'eux restent en vigueur après leur retour))


¹ Strictement parlant, ce n'est pas tout à fait vrai. Plusieurs implémentations se soucieront des variables d'environnement de localisation (LANG, LOCPATH, LC_*...), l'implémentation GNU se soucie de POSIXLY_CORRECT variable d'environnement (comparer env echo --version avec POSIXLY_CORRECT=1 env echo --version sur un GNU).

43
Stéphane Chazelas

Vous le faites correctement, mais la syntaxe bash est facile à mal interpréter: vous pourriez penser que echo $TEST fait que echo récupère TEST env var puis l'imprime, ce n'est pas le cas. Donc donné

export TEST=123

puis

TEST=456 echo $TEST

implique la séquence suivante:

  1. Le shell analyse toute la ligne de commande et exécute toutes les substitutions de variables, de sorte que la ligne de commande devient

    TEST=456 echo 123
    
  2. Il crée les variables temporaires définies avant la commande, il enregistre donc la valeur actuelle de TEST et l'écrase avec 456; la ligne de commande est maintenant

    echo 123
    
  3. Il exécute la commande restante, qui dans ce cas imprime 123 sur stdout (donc la commande Shell qui reste n'a même pas utilisé la valeur temporaire de TEST)

  4. Il restaure la valeur de TEST

Utilisez plutôt printenv, car cela n'implique pas de substitution de variable:

>> export TEST=123
>> printenv TEST
123
>> TEST=456 printenv TEST
456
>> printenv TEST && TEST=456 printenv TEST && TEST=789 printenv TEST && printenv TEST
123
456
789
123
>>
10
Oliver

Vous pouvez faire fonctionner cela en utilisant:

TEST=foo && echo $TEST
5
pradeepchhetri