web-dev-qa-db-fra.com

Pourquoi "A = 10 echo $ A" n'imprime pas 10?

Cette commande:

A=10 echo $A

affiche une ligne vide. Pourquoi pas 10? Pourquoi le paramètre d'environnement temporaire sur place ne fonctionne-t-il pas?

Je veux connaître la raison et l'explication plutôt que la solution.

J'ai utilisé

LANG=C gcc ...

pour forcer gcc, utilisez la langue de secours (anglais) au lieu de la langue système (chinois). Donc, je suppose qu'un préfixe VAR=value va configurer un environnement temporaire pour la commande qui le suit. Mais il semble que j'ai un malentendu.

25
Earth Engine

C'est une question d'ordre dans lequel les différentes étapes d'évaluation d'une commande se déroulent.

A=10 echo $A analyse d'abord la commande en une commande simple composée de trois mots A=10, echo et $A. Ensuite, chaque mot subit une substitution de variable, c’est-à-dire la transformation des extensions de variable telles que $A en leurs valeurs (j’élimine les étapes qui ne font rien de visible).

Si A a initialement la valeur foo, le résultat des étapes de développement est une commande simple comportant encore trois mots: A=10, echo et foo. (Le shell se souvient également à ce stade des caractères qui se trouvaient initialement entre guillemets - dans ce cas, aucun.) L'étape suivante consiste à exécuter la commande. Puisque A=10 commence par un nom de variable valide suivi d'un signe égal, il est traité comme une affectation. la variable A est définie sur 10 à la fois dans l'environnement de ligne de commande et dans l'environnement au cours de l'exécution de la commande. (Normalement, vous devez écrire export A pour avoir A dans l'environnement et pas seulement en tant que variable Shell; il s'agit d'une exception.) Le prochain mot n'est pas une affectation; il est donc traité comme un nom de commande (il s'agit d'une commande intégrée). . La commande echo ne dépend d'aucune variable, donc A=10 echo $A a exactement le même effet que echo $A.

Si vous souhaitez définir une variable pour la durée d'une commande uniquement, mais en tenant compte de l'affectation lors de l'exécution de la commande, vous pouvez utiliser un sous-shell. Un sous-shell, indiqué par des parenthèses, rend toutes les modifications d'état (affectations de variables, répertoire courant, définitions de fonction, etc.) locales du sous-shell.

(A=10; echo $A)

Assurez-vous que export A=10 si vous souhaitez exporter la variable vers l’environnement afin qu’elle soit vue par les programmes externes.

22
Gilles

Lorsque vous utilisez LANG=C gcc ..., le shell définit LANG pour l'environnement gccname __ niquement ​​et not ​​pour l'environnement current ​​(voir note). Ainsi, après gccname__finishes, LANGest revenu à sa valeur précédente (ou non définie).

De plus, lorsque vous utilisez A=10 echo $A, le Shell remplace $ A, pas l'écho, et cette substitution (appelée "expansion") survient avant ​​l'instruction est évaluée (y compris le affectation), donc pour fonctionner comme prévu Aname La valeur de __ doit être déjà définie dans l'environnement current ​​avant cette instruction.

C'est pourquoi A=10 echo $A ne fonctionne pas comme prévu: A=10 sera défini pour echo, mais echo ignore en interne la valeur de la variable d'environnement Aname__. Et $A est remplacé par la valeur définie dans le shell actuel (qui est nul), et alors passé en argument pour écho.

Votre hypothèse est donc correcte: VAR=value commandne fonctionne, mais cela n’est pertinent que si commanden interne tilise VAR. Sinon, vous pouvez toujours passer valueen tant que argument ​​à commandname__, mais les arguments sont remplacés par le shell current, ils doivent donc être définis avant l'utilisation: VAR=value; command "$VAR"

Si vous savez comment créer un script exécutable, vous pouvez essayer ceci comme test:

#!/bin/sh
echo "1st argument is $1"
echo "A is $A"

Enregistrez-le sous testscriptet essayez:

$ A=5; A=10 testscript "$A"; echo "$A"
1st argument is 5
A is 10
5

Dernier point mais non le moindre, il convient de connaître la différence entre Shell et environnement ​​variables et programme arguments.

Voici quelques bonnes références:

.

(*) Remarque: techniquement, le shell ne est également défini dans l'environnement actuel, et voici pourquoi: Certaines commandes, telles que echoname__, readet testsont Construits dans le shell, et comme tels ne pas engendrer un processus enfant. Ils fonctionnent dans l'environnement actuel. Mais le shell veille à ce que l’affectation ne dure que jusqu’à ce que la commande soit exécutée. Par conséquent, pour des raisons pratiques, l’effet est le même: l’affectation n’est vue que par cette seule commande.

37
MestreLion

Un moyen éventuellement propre de faire ce que vous désirez apparemment est de lancer la commande:

A=10 eval 'echo $A'

Ce qui retardera en fait la substitution de la valeur 10 à la place de $ A dans un contexte ultérieur (c'est-à-dire, "à l'intérieur" de l'évaluation, qui connaît déjà l'affectation). Notez que les guillemets simples sont essentiels. Une telle construction communique proprement l'affectation à la commande souhaitée (écho dans ce cas) sans risquer de polluer votre environnement actuel.

3
nhokka