Si les processus héritent de l'environnement du parent, pourquoi avons-nous besoin d'une exportation?

72

J'ai lu ici que le but d' exportun shell est de rendre la variable disponible pour les sous-processus démarrés à partir du shell.

Cependant, j'ai également lu ici et ici que "les processus héritent de leur environnement parent (le processus qui les a démarrés)".

Si tel est le cas, pourquoi avons-nous besoin export? Qu'est-ce que je rate?

Les variables shell ne font-elles pas partie de l'environnement par défaut? Quelle est la différence?

Amelio Vazquez-Reina
la source

Réponses:

75

Votre hypothèse est que les variables de shell sont dans l'environnement . Ceci est une erreur. La exportcommande est ce qui définit un nom comme étant dans l'environnement. Ainsi:

a=1 b=2
export b

renvoie le shell actuel en sachant qu'il $as'étend à 1 et $bà 2, mais les sous-processus ne sauront rien aparce qu'il ne fait pas partie de l'environnement (même dans le shell actuel).

Quelques outils utiles:

  • set: Utile pour visualiser les paramètres du shell actuel, exporté ou non
  • set -k: Définit les arguments assignés dans l'environnement. Considérerf() { set -k; env; }; f a=1
  • set -a: Indique au shell de mettre n'importe quel nom défini dans l'environnement. Comme mettre exportavant chaque mission. Utile pour les .envfichiers, comme dans set -a; . .env; set +a.
  • export: Indique au shell de mettre un nom dans l'environnement. L'exportation et l'affectation sont deux opérations totalement différentes.
  • env: En tant que commande externe, envne peut que vous renseigner sur l' environnement hérité . Il est donc utile pour la vérification de l'intégrité.
  • env -i: Utile pour effacer l'environnement avant de démarrer un sous-processus.

Alternatives à export:

  1. name=val command # Assignment before commande exporte ce nom dans la commande.
  2. declare/local -x name # Nom exporté, particulièrement utile dans les fonctions du shell lorsque vous souhaitez éviter d'exposer le nom à une portée extérieure.
  3. set -a # Exporte chaque affectation suivante.
kojiro
la source
3
set -kest tel qu'on peut utiliser cmd ENVVAR=valueà la place de ENVVAR=value cmd, cela ne fonctionnera pas dans votre exemple à moins d'avoir set -kété exécuté avant d'appeler f. De plus, peu de shell le supporte de nos jours et uniquement pour des raisons de compatibilité avec le shell Bourne. Dans le shell Bourne (ou Korn), cela ne fonctionnerait pas pour les fonctions. Et comme cela affecte l'analyse syntaxique du shell, il doit être en vigueur au moment où le shell lit le code qui l'utilise.
Stéphane Chazelas
1
Vous voudrez peut-être aussi mentionnerset -a
Stéphane Chazelas
24

Il y a une différence entre les variables shell et les variables d'environnement. Si vous définissez une variable shell sans la exportremplacer, elle n’est pas ajoutée à l’environnement des processus et n’est donc pas héritée de ses enfants.

En utilisant, exportvous indiquez au shell d'ajouter la variable shell à l'environnement. Vous pouvez tester cela en utilisant printenv(qui affiche simplement son environnement stdout, puisqu'il s'agit d'un processus enfant, vous voyez l'effet des exportvariables ing):

#!/bin/sh

MYVAR="my cool variable"

echo "Without export:"
printenv | grep MYVAR

echo "With export:"
export MYVAR
printenv | grep MYVAR
Andreas Wiese
la source
6

Une variable, une fois exportée, fait partie de l'environnement. PATHest exporté dans le shell lui-même, tandis que les variables personnalisées peuvent être exportées selon les besoins. En utilisant un code d'installation:

$ cat subshell.sh 
#!/usr/bin/env bash
declare | grep -e '^PATH=' -e '^foo='

Comparer

$ cat test.sh 
#!/usr/bin/env bash
export PATH=/bin
export foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test.sh 
PATH=/bin
foo=bar
PATH=/bin
foo=bar

Avec

$ cat test2.sh 
#!/usr/bin/env bash
PATH=/bin
foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test2.sh 
PATH=/bin
foo=bar
PATH=/bin

Comme foon’est pas exporté par le shell et test2.shne l’a jamais exporté, il ne faisait pas partie de l’environnement de subshell.shla dernière exécution.

l0b0
la source