Je viens de rencontrer un problème qui me montre que je ne suis pas clair sur la portée des variables du shell.
J'essayais d'utiliser bundle install
, qui est une commande Ruby qui utilise la valeur de $GEM_HOME
pour faire son travail. J'avais défini $GEM_HOME
, mais la commande a ignoré cette valeur jusqu'à ce que je l'utilise export
, comme dans export GEM_HOME=/some/path
.
J'ai lu que cela rend la variable "globale" (ou variable d'environnement ), mais je ne comprends pas ce que cela signifie. Je connais les globals dans la programmation, mais pas parmi les programmes distincts.
De plus, étant donné que ma configuration de telles variables ne s'applique qu'à la session shell en cours, comment pourrais-je les définir pour, par exemple, un processus démonisé?
Quelles portées peuvent avoir les variables de shell?
la source
FOO=bar
, cela définit la valeur du processus shell en cours. Si je lance ensuite un programme comme (bundle install
), cela crée un processus enfant, auquel il n’a pas accèsFOO
. Mais si j'avais ditexport FOO=bar
, le processus enfant (et ses descendants) y auraient accès. L'un d'eux pourrait, à son tour, appelerexport FOO=buzz
pour changer la valeur pour ses descendants, ou simplementFOO=buzz
pour changer la valeur uniquement pour elle-même. Est-ce à peu près correct?Au moins les valeurs inférieures
ksh
et inférieuresbash
, les variables peuvent avoir trois portées, et non deux comme le sont actuellement toutes les réponses restantes.Outre les étendues de variable exportée (c'est-à-dire d'environnement) et de variable non exportée dans le shell, il en existe une troisième plus étroite pour les variables locales de fonction.
Les variables déclarées dans les fonctions du shell avec le
typeset
jeton ne sont visibles qu'à l'intérieur des fonctions dans lesquelles elles sont déclarées et des (sous-fonctions) appelées à partir de là.Ce
ksh
/bash
code:produit cette sortie:
Comme vous pouvez le constater, la variable exportée est affichée à partir des trois premiers emplacements, les variables non exportées ne sont pas affichées en dehors du shell actuel et la variable locale de la fonction n'a aucune valeur en dehors de la fonction elle-même. Le dernier test n'affiche aucune valeur, car les variables exportées ne sont pas partagées entre les shells, c'est-à-dire qu'elles peuvent uniquement être héritées et que la valeur héritée ne peut plus être affectée par le shell parent.
Notez que ce dernier comportement est assez différent de celui de Windows dans lequel vous pouvez utiliser des variables système entièrement globales et partagées par tous les processus.
la source
Ils sont étendus par processus
Les autres intervenants m'ont aidé à comprendre que la portée des variables shell concerne les processus et leurs descendants .
Lorsque vous tapez une commande comme
ls
sur la ligne de commande, vous êtes en train de forger un processus pour exécuter lels
programme. Le nouveau processus a votre shell comme parent.Tout processus peut avoir ses propres variables "locales", qui ne sont pas transmises aux processus enfants. Il peut également définir des variables "d'environnement", qui sont. Utiliser
export
crée une variable d'environnement. Dans les deux cas, les processus indépendants (homologues de l'original) ne verront pas la variable. nous ne contrôlons que ce que les processus enfants voient.Supposons que vous ayez un shell bash, que nous appellerons A. Vous tapez
bash
, ce qui crée un shell bash de processus enfant, que nous appellerons B. Tout ce que vous avez appeléexport
en A sera toujours défini en B.Maintenant, en B, vous dites
FOO=b
. Une des deux choses va se passer:FOO
, il créera une variable locale. Les enfants de B ne l’auront pas (à moins que B n’appelleexport
).FOO
, il la modifiera pour elle-même et ses enfants ensuite créés . Les enfants de B verront la valeur attribuée par B. Cependant, cela n'affectera pas du tout A.Voici une démo rapide.
Tout cela explique mon problème initial: je me suis installé
GEM_HOME
dans mon shell, mais lorsque j'ai appelébundle install
, cela a créé un processus enfant. Parce que je n'avais pas utiliséexport
, le processus enfant n'a pas reçu le shellGEM_HOME
.Exportation
Vous pouvez "dés-exporter" une variable - en l'empêchant d'être transmise aux enfants - en utilisant
export -n FOO
.la source
La meilleure explication que je puisse trouver sur l'exportation est celle-ci:
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
La variable définie dans un sous-shell ou un shell enfant est uniquement visible par le sous-shell dans lequel elle est définie. La variable exportée est réellement transformée en une variable d’environnement. Donc, pour être clair, vous
bundle install
exécutez son propre shell qui ne le voit pas$GEM_HOME
sauf si uneenvironment
variable est également exportée.Vous pouvez consulter la documentation sur la portée variable ici:
http://www.tldp.org/LDP/abs/html/subshells.html
la source
FOO=bar
; vous devez utiliserexport
pour en faire un. Question corrigée en conséquence.Il existe une hiérarchie d'étendues variables, comme prévu.
Environnement
L'envergure la plus externe est l'environnement. Il s'agit du seul domaine géré par le système d'exploitation. Il est donc garanti qu'il existe pour chaque processus. Lorsqu'un processus est démarré, il reçoit une copie de l'environnement de son parent, après quoi les deux deviennent indépendants: la modification de l'environnement de l'enfant ne modifie pas celui du parent, et la modification de l'environnement du parent ne modifie pas celui d'un enfant existant.
Variables shell
Les coquilles ont leur propre notion de variables. C’est là que les choses commencent à devenir un peu déroutantes.
Lorsque vous affectez une valeur à une variable dans un shell et que cette variable existe déjà dans l'environnement, la variable d'environnement reçoit la nouvelle valeur. Toutefois, si la variable ne figure pas encore dans l'environnement, elle devient une variable shell . Les variables shell n'existent que dans le processus shell, de la même manière que les variables Ruby n'existent que dans un script Ruby. Ils ne sont jamais hérités par les processus enfants.
Voici où le
export
mot clé entre en jeu. Il copie une variable shell dans l'environnement du processus shell, ce qui permet aux processus enfants d'hériter.Variables locales
Les variables locales sont des variables shell étendues aux blocs de code les contenant. Vous déclarez des variables locales avec le
typeset
mot - clé (portable) oulocal
oudeclare
(Bash). Comme pour les autres variables du shell, les processus enfants n'héritent pas des variables locales. De plus, les variables locales ne peuvent pas être exportées.la source