Pourquoi "A = 10 echo $ A" ne pas imprimer 10?

24

Cette commande:

A=10 echo $A

imprime une ligne vide. Pourquoi pas 10 ? Pourquoi le paramètre d'environnement temporaire en 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 à utiliser la langue de secours (anglais) au lieu de la langue du système (chinois). Je suppose donc 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.

    
posée Earth Engine 28.05.2014 - 13:25
la source

3 réponses

21

Il s'agit de l'ordre dans lequel les différentes étapes d'évaluation d'une commande se produisent.

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 variables telles que $A en leurs valeurs (je omet les étapes qui ne font rien de visible).

Si A a la valeur foo initialement, le résultat des étapes d’expansion est une commande simple qui comporte toujours trois mots: A=10 , echo et foo . (Le shell se souvient également à ce stade quels caractères étaient 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 le shell et l'environnement lors de l'exécution de la commande. (Normalement, vous devez écrire export A pour avoir A dans l'environnement et pas seulement comme variable shell; c'est une exception.) Le mot suivant n'est pas une affectation, donc il est traité comme un nom de commande -en commande). 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 tous les changements d’état (affectations de variables, répertoire en cours, définitions de fonctions, etc.) au sous-shell.

(A=10; echo $A)

Faites que export A=10 si vous voulez exporter la variable dans l’environnement pour qu’il soit vu par les programmes externes.

    
réponse donnée Gilles 29.05.2014 - 03:00
la source
36

Lorsque vous utilisez LANG=C gcc ... , le shell définit LANG pour l'environnement seulement de gcc et non pour le courant environnement lui-même ( voir note ). Ainsi, après gcc , LANG revient à sa valeur précédente (ou non définie).

De plus, lorsque vous utilisez A=10 echo $A , c'est le shell qui remplace $ A, pas l’écho, et cette substitution (appelée "expansion") se produit avant l’instruction est évalué (y compris l'assignation), donc pour travailler comme prévu, la valeur de A doit déjà être définie dans l'environnement actuel 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 A . Et $A est remplacé par la valeur définie dans le shell actuel (qui est nul), et puis transmis en argument à echo.

Votre hypothèse est donc correcte: VAR=value command fait fonctionner, mais cela n’est pertinent que si command interne utilise VAR. Sinon, vous pouvez toujours transmettre value comme argument à command , mais les arguments sont remplacés par le shell current , ils doivent donc être définis avant leur utilisation: VAR=value; command "$VAR"

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

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

Enregistrez-le sous testscript et essayez:

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

Last but not least, il est utile de connaître la différence entre les variables shell et environment et les arguments de programme .

Voici quelques bonnes références:

.

(*) Note: techniquement, le shell fait dans l'environnement actuel, et voici pourquoi: Certaines commandes, telles que echo , read et test sont des shell intégrées , et à ce titre, ils ne génèrent pas de processus enfant. Ils fonctionnent dans l'environnement actuel. Mais le shell prend soin que l'assignation ne dure que jusqu'à l'exécution de la commande, donc pour des raisons pratiques, l'effet est le même: l'assignation n'est vue que par cette seule commande.

    
réponse donnée MestreLion 28.05.2014 - 13:37
la source
2

Une manière possible de faire ce que vous désirez est d’émettre la commande:

A=10 eval 'echo $A'

Ce qui reportera en effet la substitution de la valeur 10 à la place de $ A dans un contexte ultérieur (ie, "à 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.

    
réponse donnée nhokka 29.05.2014 - 07:48
la source

Lire d'autres questions sur les étiquettes