Définition d'une variable avec ou sans exportation

956

À quoi ça sert export?

Quelle est la différence entre:

export name=value

et

name=value
fil volant
la source
4
Notez tangentiellement aussi que ce export name=valuen'est pas portable. Selon ce que vous voulez exactement, essayez name=value; export nameune solution portable.
tripleee

Réponses:

1055

export met la variable à la disposition des sous-processus.

C'est,

export name=value

signifie que le nom de la variable est disponible pour tout processus que vous exécutez à partir de ce processus shell. Si vous souhaitez qu'un processus utilise cette variable, utilisez exportet exécutez le processus à partir de ce shell.

name=value

signifie que la portée variable est limitée au shell et n'est disponible pour aucun autre processus. Vous l'utiliseriez pour (par exemple) les variables de boucle, les variables temporaires, etc.

Il est important de noter que l'exportation d'une variable ne la rend pas disponible pour les processus parents. En d'autres termes, la spécification et l'exportation d'une variable dans un processus généré ne la rend pas disponible dans le processus qui l'a lancée.

Brian Agnew
la source
105
Plus précisément, l'exportation met la variable à la disposition des processus enfants via l'environnement.
Beano
15
J'ajouterais également que si l'exportation se trouve dans un fichier que vous "source" (comme. Filename), il l'exporte également dans votre environnement de travail.
rogerdpack
6
@rogerdpack ne pouvez-vous pas faire cela sans exporter? cat> blah \ na = hi \ n. blabla; écho $ a; sorties «salut» pour moi.
David Winiecki
2
Bien, cela fonctionne même sans l'exportation. Donc, je suppose que lors de l'approvisionnement d'un fichier, si vous utilisez l'exportation, il se reflétera dans les processus enfants, sinon, cela affectera simplement l'environnement local bash ...
rogerdpack
19
Il y a un cas particulier à cela; name=value command ne faire la variable disponible dans le sous-processus command.
Oliver Charlesworth
254

Pour illustrer ce que disent les autres réponses:

$ foo="Hello, World"
$ echo $foo
Hello, World
$ bar="Goodbye"
$ export foo
$ bash
bash-3.2$ echo $foo
Hello, World
bash-3.2$ echo $bar

bash-3.2$ 
alxp
la source
9
Un autre exemple pour celaal$ foobar="Whatever" bash
Alun
70

D'autres ont répondu que l'exportation rend la variable disponible pour les sous-coquilles, et c'est correct mais simplement un effet secondaire. Lorsque vous exportez une variable, elle place cette variable dans l'environnement du shell actuel (c'est-à-dire que le shell appelle putenv(3)ou setenv(3)).
L'environnement d'un processus est hérité à travers exec, rendant la variable visible dans les sous-coquilles.

Edit (avec une perspective de 5 ans): c'est une réponse idiote. Le but de l '«exportation» est de faire en sorte que les variables «soient dans l'environnement des commandes exécutées ultérieurement», que ces commandes soient des sous-coquilles ou des sous-processus. Une implémentation naïve serait de simplement mettre la variable dans l'environnement du shell, mais cela rendrait l'implémentation impossible export -p.

William Pursell
la source
6
Notez que ce n'est pas entièrement vrai. Dans bash, l'exportation ajoute en effet la variable à l'environnement du shell courant, mais ce n'est pas le cas avec dash. Il me semble que l'ajout de la variable à l'environnement du shell actuel est le moyen le plus simple d'implémenter la sémantique de export, mais ce comportement n'est pas obligatoire.
William Pursell
7
Je ne sais pas ce que cela dasha à voir. L'affiche originale posait une question spécifique bash.
Starfish
14
La question est balisée bashmais s'applique également à toute variante de bourne-shell. Être trop précis et fournir des réponses qui ne s'appliquent qu'à bashest un grand mal.
William Pursell
12
bashest la jQuery du shell.
Potherca
2
export makes the variable available to subshells, and that is correctIl s'agit d'une utilisation très déroutante de la terminologie. Les sous-coquilles n'ont pas besoin exportd'hériter de variables. Les sous-processus le font.
Amit Naidu
62

Il a été dit qu'il n'est pas nécessaire d'exporter en bash lors de la ponte des sous-coquilles, tandis que d'autres ont dit exactement le contraire. Il est important de noter la différence entre les sous - shells (ceux qui sont créés par (), ``, $()ou boucles) et des sous - processus (processus qui sont invoqués par nom, par exemple un littéral bashapparaissant dans votre script).

  • Les sous- shells auront accès à toutes les variables du parent, quel que soit leur état exporté.
  • Sous les processus seront seulement voir les variables exportées.

Ce qui est courant dans ces deux constructions, c'est que ni l'une ni l'autre ne peut retransmettre des variables au shell parent.

$ noexport=noexport; export export=export; (echo subshell: $noexport $export; subshell=subshell); bash -c 'echo subprocess: $noexport $export; subprocess=subprocess'; echo parent: $subshell $subprocess
subshell: noexport export
subprocess: export
parent:

Il existe une autre source de confusion: certains pensent que les sous-processus «fourchus» sont ceux qui ne voient pas les variables non exportées. En général, les fork () sont immédiatement suivis des exec (), et c'est pourquoi il semblerait que le fork () soit la chose à rechercher, alors qu'en fait c'est le exec (). Vous pouvez exécuter des commandes sans fork () en premier avec la execcommande, et les processus démarrés par cette méthode n'auront pas non plus accès aux variables non exportées:

$ noexport=noexport; export export=export; exec bash -c 'echo execd process: $noexport $export; execd=execd'; echo parent: $execd
execd process: export

Notez que nous ne voyons pas la parent:ligne cette fois, car nous avons remplacé le shell parent par la execcommande, il ne reste donc plus rien pour exécuter cette commande.

Matyas Koszik
la source
Je n'ai jamais vu de boucle qui (par elle-même) a créé un sous-shell; OTOH un pipeline fait (toujours pour des pièces autres que la dernière, parfois pour la dernière selon votre shell, votre version et vos options). Backgrounding ( &) crée également un sous-shell.
dave_thompson_085
Qu'en est-il de ces var=asdf bash -c 'echo $var'ou var=asdf exec bash -c 'echo $var'? La sortie est asdf. Le ;fait la différence s'il est placé après la définition de la variable. Quelle serait l'explication? Il ressemble en quelque sorte var(sans ;) au sous-processus généré, car le shell d'origine n'a rien à voir avec cela. echo $varn'imprime rien s'il est exécuté sur la deuxième ligne. Mais une ligne var=asdf bash -c 'echo $var'; echo $vardonne asdf\nasdf.
4xy
31

export NAME=value pour les paramètres et les variables qui ont un sens pour un sous-processus.

NAME=value pour les variables temporaires ou de boucle privées du processus shell en cours.

Plus en détail, exportmarque le nom de la variable dans l'environnement qui copie dans un sous-processus et ses sous-processus lors de la création. Aucun nom ou valeur n'est jamais recopié à partir du sous-processus.

  • Une erreur courante consiste à placer un espace autour du signe égal:

    $ export FOO = "bar"  
    bash: export: `=': not a valid identifier
  • Seule la variable exportée ( B) est vue par le sous-processus:

    $ A="Alice"; export B="Bob"; echo "echo A is \$A. B is \$B" | bash
    A is . B is Bob
  • Les modifications du sous-processus ne modifient pas le shell principal:

    $ export B="Bob"; echo 'B="Banana"' | bash; echo $B
    Bob
  • Les variables marquées pour l'exportation ont des valeurs copiées lors de la création du sous-processus:

    $ export B="Bob"; echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash &
    [1] 3306
    $ B="Banana"; echo '(sleep 30; echo "Subprocess 2 has B=$B")' | bash 
    Subprocess 1 has B=Bob
    Subprocess 2 has B=Banana
    [1]+  Done         echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash
  • Seules les variables exportées font partie de l'environnement ( man environ):

     $ ALICE="Alice"; export BOB="Bob"; env | grep "ALICE\|BOB"
     BOB=Bob

Alors maintenant, il devrait être aussi clair que le soleil de l'été! Merci à Brain Agnew, alexp et William Prusell.

Charles Merriam
la source
12

export rendra la variable accessible à tous les shells issus du shell courant.

John T
la source
11

Il convient de noter que vous pouvez exporter une variable et modifier ultérieurement la valeur. La valeur modifiée de la variable sera disponible pour les processus enfants. Une fois que l'exportation a été définie pour une variable, vous devez faire export -n <var>pour supprimer la propriété.

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset
Brian S. Wilson
la source
Merci, c'est exactement les informations que je cherchais car j'ai vu un script qui utilisait des variables d'environnement et les "réexportait" avec une nouvelle valeur, et je me demandais si c'était nécessaire.
Mike Lippert
8

Comme vous le savez peut-être déjà, UNIX permet aux processus d'avoir un ensemble de variables d'environnement, qui sont des paires clé / valeur, la clé et la valeur étant des chaînes. Le système d'exploitation est chargé de conserver ces paires pour chaque processus séparément.

Le programme peut accéder à ses variables d'environnement via cette API UNIX:

  • char *getenv(const char *name);
  • int setenv(const char *name, const char *value, int override);
  • int unsetenv(const char *name);

Les processus héritent également des variables d'environnement des processus parents. Le système d'exploitation est responsable de la création d'une copie de tous les "envars" au moment où le processus enfant est créé.

Bash , entre autres shells, est capable de définir ses variables d'environnement à la demande de l'utilisateur. C'est exportpour ça.

exportest une commande Bash pour définir la variable d'environnement pour Bash. Toutes les variables définies avec cette commande seraient héritées par tous les processus que ce Bash créerait.

En savoir plus sur l' environnement à Bash

Un autre type de variable dans Bash est la variable interne. Puisque Bash n'est pas seulement un shell interactif, c'est en fait un interpréteur de script, comme tout autre interpréteur (par exemple Python), il est capable de conserver son propre ensemble de variables. Il convient de mentionner que Bash (contrairement à Python) ne prend en charge que les variables de chaîne.

La notation pour la définition des variables Bash est name=value. Ces variables restent dans Bash et n'ont rien à voir avec les variables d'environnement conservées par le système d'exploitation.

En savoir plus sur les paramètres du shell (y compris les variables)

Il convient également de noter que, selon le manuel de référence de Bash:

L'environnement de toute commande ou fonction simple peut être temporairement augmenté en le préfixant avec des affectations de paramètres, comme décrit dans Paramètres du shell . Ces instructions d'affectation affectent uniquement l'environnement vu par cette commande.


Pour résumer:

  • exportest utilisé pour définir la variable d'environnement dans le système d'exploitation. Cette variable sera disponible pour tous les processus enfants créés par le processus Bash actuel pour toujours.
  • La notation des variables Bash (nom = valeur) est utilisée pour définir les variables locales disponibles uniquement pour le processus actuel de bash
  • La notation de variable Bash préfixant une autre commande crée une variable d'environnement uniquement pour la portée de cette commande.
progalgo
la source
1
Les vars bash ne prennent pas en charge autant de types que Python, mais ont une chaîne, un entier et deux types de tableau ('indexé' / traditionnel et 'associatif' qui est similaire au tableau awk, au hachage perl ou au dict Python). Les autres coquilles varient; seule la chaîne est portable .
dave_thompson_085
7

La réponse acceptée implique cela, mais je voudrais rendre explicite la connexion aux commandes internes du shell:

Comme déjà mentionné, exportrendra une variable disponible à la fois pour le shell et les enfants. Si exportn'est pas utilisé, la variable ne sera disponible que dans le shell, et seules les commandes internes du shell pourront y accéder.

C'est,

tango=3
env | grep tango # prints nothing, since env is a child process
set | grep tango # prints tango=3 - "type set" shows `set` is a shell builtin
flow2k
la source
3

Voici encore un autre exemple:

VARTEST="value of VARTEST" 
#export VARTEST="value of VARTEST" 
sudo env | grep -i vartest 
sudo echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}" 
sudo bash -c 'echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}"'  

Ce n'est qu'en utilisant l'exportation VARTEST que la valeur de VARTEST est disponible dans sudo bash -c '...'!

Pour d'autres exemples, voir:


la source
3

Deux des créateurs d'UNIX, Brian Kernighan et Rob Pike, l'expliquent dans leur livre "The UNIX Programming Environment". Google pour le titre et vous trouverez facilement une version pdf.

Ils traitent des variables shell dans la section 3.6, et se concentrent sur l'utilisation de la exportcommande à la fin de cette section:

Lorsque vous souhaitez rendre la valeur d'une variable accessible dans des sous-shells, la commande d'exportation du shell doit être utilisée. (Vous pourriez penser à pourquoi il n'y a aucun moyen d'exporter la valeur d'une variable d'un sous-shell vers son parent).

Dan Carter
la source
2

Juste pour montrer la différence entre une variable exportée se trouvant dans l'environnement (env) et une variable non exportée ne se trouvant pas dans l'environnement:

Si je fais ça:

$ MYNAME=Fred
$ export OURNAME=Jim

alors seulement $ OURNAME apparaît dans l'env. La variable $ MYNAME n'est pas dans l'env.

$ env | grep NAME
OURNAME=Jim

mais la variable $ MYNAME existe dans le shell

$ echo $MYNAME
Fred
Volonté
la source
1

Par défaut, les variables créées dans un script ne sont disponibles que pour le shell courant; les processus enfants (sous-shells) n'auront pas accès aux valeurs qui ont été définies ou modifiées. Pour permettre aux processus enfants de voir les valeurs, vous devez utiliser la commande d'exportation.

Amjad
la source
0

Bien que cela ne soit pas explicitement mentionné dans la discussion, il n'est PAS nécessaire d'utiliser l'export lors de la génération d'un sous-shell depuis bash puisque toutes les variables sont copiées dans le processus enfant.

Scott
la source
Veuillez expliquer que ce que vous dites semble contredire directement les réponses avec les exemples ci-dessus.
Mike Lippert
C'est la bonne façon si vous ne voulez pas que les variables soient exportées globalement mais seulement disponibles pour le sous-processus! Je vous remercie.
jtblin