Definizione di una variabile con o senza esportazione


955

A cosa serve export?

Qual è la differenza tra:

export name=value

e

name=value

4
Si noti anche tangenzialmente che export name=valuenon è portatile. A seconda di cosa esattamente vuoi, prova name=value; export nameper una soluzione portatile.
Tripleee

Risposte:


1054

export rende la variabile disponibile per i sottoprocessi.

Questo è,

export name=value

significa che il nome della variabile è disponibile per qualsiasi processo eseguito da quel processo di shell. Se si desidera che un processo utilizzi questa variabile, utilizzare exported eseguire il processo da quella shell.

name=value

significa che l'ambito variabile è limitato alla shell e non è disponibile per nessun altro processo. Lo useresti per (diciamo) variabili di loop, variabili temporanee ecc.

È importante notare che l'esportazione di una variabile non la rende disponibile per i processi padre. Cioè, specificare ed esportare una variabile in un processo generato non la rende disponibile nel processo che l'ha lanciata.


105
In particolare, l'esportazione rende la variabile disponibile per i processi figlio tramite l'ambiente.
Beano,

15
Aggiungo anche che se l'esportazione si trova in un file "sorgente" (come .file), lo esporta anche nell'ambiente di lavoro.
rogerdpack,

6
@rogerdpack non puoi farlo senza esportazione? gatto> blah \ na = ciao \ n. bla; echo $ a; genera "ciao" per me.
David Winiecki,

2
Bello funziona anche senza esportazione. Quindi suppongo che quando si
procede all'approvvigionamento di

19
C'è un caso limite in questo; name=value command non rendere la variabile disponibile nel sub-processo command.
Oliver Charlesworth il

254

Per illustrare cosa dicono le altre risposte:

$ 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$ 

9
Un altro esempio per questoal$ foobar="Whatever" bash
Alun,

70

Altri hanno risposto che l'esportazione rende la variabile disponibile per i subshells, e questo è corretto ma solo un effetto collaterale. Quando si esporta una variabile, questa viene inserita nell'ambiente della shell corrente (ovvero la shell chiama putenv(3)o setenv(3)).
L'ambiente di un processo è ereditato da exec, rendendo visibile la variabile in subshells.

Modifica (con una prospettiva di 5 anni): questa è una risposta sciocca. Lo scopo di "export" è di far sì che le variabili "si trovino nell'ambiente di comandi eseguiti successivamente", indipendentemente dal fatto che tali comandi siano subshells o sottoprocessi. Un'implementazione ingenua sarebbe semplicemente mettere la variabile nell'ambiente della shell, ma ciò renderebbe impossibile l'implementazione export -p.


6
Si noti che questo non è del tutto vero. In bash, export effettivamente aggiunge la variabile all'ambiente della shell corrente, ma non è così dash. Mi sembra che aggiungere la variabile all'ambiente della shell corrente sia il modo più semplice per implementare la semantica di export, ma quel comportamento non è obbligatorio.
William Pursell,

7
Non sono sicuro di cosa dashabbia a che fare con questo. Il poster originale chiedeva specificamente bash.
Starfish,

14
La domanda è taggata bashma si applica ugualmente a qualsiasi variante bourne-shell. Essere eccessivamente specifici e fornire risposte che si applicano solo a bashè un grande male.
William Pursell,

12
bashè il jQuery della shell.
Potherca,

2
export makes the variable available to subshells, and that is correctQuesto è un uso molto confuso della terminologia. I sub-shell non devono exportereditare le variabili. I sottoprocessi fanno.
Amit Naidu,

62

È stato detto che non è necessario esportare in bash quando si generano subshells, mentre altri hanno affermato l'esatto contrario. E 'importante notare la differenza tra sottoshell (quelli che vengono creati (), ``, $()o loop) e sottoprocessi (processi che vengono richiamati in base al nome, ad esempio, un letterale bashche appare nello script).

  • Le sotto shell avranno accesso a tutte le variabili dal genitore, indipendentemente dal loro stato esportato.
  • I processi secondari vedranno solo le variabili esportate.

Ciò che è comune in questi due costrutti è che nessuno dei due può restituire le variabili alla shell genitore.

$ 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:

C'è un'altra fonte di confusione: alcuni pensano che i sottoprocessi "biforcati" siano quelli che non vedono variabili non esportate. Di solito fork () s è immediatamente seguito da exec () s, ed è per questo che sembra che fork () sia la cosa da cercare, mentre in realtà è exec (). È possibile eseguire i comandi senza fork () ing prima con il execcomando e anche i processi avviati con questo metodo non avranno accesso alle variabili non esportate:

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

Nota che parent:questa volta non vediamo la linea, perché abbiamo sostituito la shell genitore con il execcomando, quindi non è rimasto nulla per eseguire quel comando.


Non ho mai visto un ciclo che (da solo) ha creato una subshell; OTOH fa una pipeline (sempre per pezzi diversi dall'ultimo, a volte per l'ultimo a seconda della shell, della versione e delle opzioni). Backgrounding ( &) crea anche una subshell.
dave_thompson_085,

Che dire di questi var=asdf bash -c 'echo $var'o var=asdf exec bash -c 'echo $var'? L'output è asdf. La ;fa differenza se posizionato dopo la definizione della variabile. Quale sarebbe la spiegazione? Sembra che i var(senza alcuno ;) rispetto ai sottoprocessi generati in qualche modo, a causa della shell di origine non abbiano nulla a che fare con esso. echo $varnon stampa nulla se eseguito sulla seconda riga. Ma uno allineato var=asdf bash -c 'echo $var'; echo $varasdf\nasdf.
4

31

export NAME=value per impostazioni e variabili che hanno significato per un sottoprocesso.

NAME=value per variabili temporanee o cicliche private al processo di shell corrente.

Più in dettaglio, exportcontrassegna il nome della variabile nell'ambiente che viene copiato in un sottoprocesso e i relativi sottoprocessi al momento della creazione. Nessun nome o valore viene mai copiato dal sottoprocesso.

  • Un errore comune è quello di posizionare uno spazio attorno al segno uguale:

    $ export FOO = "bar"  
    bash: export: `=': not a valid identifier
  • Solo la variabile esportata (B ) viene visualizzata dal sottoprocesso:

    $ A="Alice"; export B="Bob"; echo "echo A is \$A. B is \$B" | bash
    A is . B is Bob
  • Le modifiche al sottoprocesso non cambiano la shell principale:

    $ export B="Bob"; echo 'B="Banana"' | bash; echo $B
    Bob
  • Le variabili contrassegnate per l'esportazione hanno valori copiati quando viene creato il sottoprocesso:

    $ 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
  • Solo le variabili esportate diventano parte dell'ambiente ( man environ):

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

Quindi, ora dovrebbe essere chiaro come il sole estivo! Grazie a Brain Agnew, alexp e William Prusell.


12

export renderà la variabile disponibile per tutte le shell biforcute dalla shell corrente.


11

Va notato che è possibile esportare una variabile e successivamente modificare il valore. Il valore modificato della variabile sarà disponibile per i processi figlio. Una volta impostata l'esportazione per una variabile, è necessario eseguire la export -n <var>rimozione della proprietà.

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset

Grazie, queste sono esattamente le informazioni che stavo cercando perché ho visto uno script che utilizzava le variabili di ambiente e poi le "riesportava" con un nuovo valore, e mi chiedevo se fosse necessario.
Mike Lippert,

8

Come forse già saprai, UNIX consente ai processi di avere una serie di variabili d'ambiente, che sono coppie chiave / valore, sia chiave che valore sono stringhe. Il sistema operativo è responsabile del mantenimento separato di queste coppie per ciascun processo.

Il programma può accedere alle sue variabili di ambiente tramite questa API UNIX:

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

I processi ereditano anche le variabili di ambiente dai processi parent. Il sistema operativo è responsabile della creazione di una copia di tutti gli "aspetti" al momento della creazione del processo figlio.

Bash , tra le altre shell, è in grado di impostare le sue variabili di ambiente su richiesta dell'utente. Questo è ciò che exportesiste.

exportè un comando Bash per impostare la variabile di ambiente per Bash. Tutte le variabili impostate con questo comando sarebbero ereditate da tutti i processi che questo Bash creerebbe.

Altro su Ambiente in Bash

Un altro tipo di variabile in Bash è la variabile interna. Poiché Bash non è solo una shell interattiva, in realtà è un interprete di script, come qualsiasi altro interprete (ad esempio Python) è in grado di mantenere il proprio set di variabili. Va detto che Bash (a differenza di Python) supporta solo variabili stringa.

Notazione per la definizione delle variabili di Bash è name=value. Queste variabili rimangono all'interno di Bash e non hanno nulla a che fare con le variabili di ambiente gestite dal sistema operativo.

Altre informazioni sui parametri della shell (comprese le variabili)

Vale anche la pena notare che, secondo il manuale di riferimento di Bash:

L'ambiente per qualsiasi comando o funzione semplice può essere temporaneamente aumentato aggiungendolo con assegnazioni di parametri, come descritto in Parametri Shell . Queste istruzioni di assegnazione influiscono solo sull'ambiente visto da quel comando.


Per riassumere:

  • exportviene utilizzato per impostare la variabile di ambiente nel sistema operativo. Questa variabile sarà disponibile per tutti i processi figlio creati dall'attuale processo Bash in seguito.
  • La notazione della variabile Bash (nome = valore) viene utilizzata per impostare le variabili locali disponibili solo per l'attuale processo di bash
  • La notazione della variabile Bash che precede un altro comando crea la variabile di ambiente solo per l'ambito di quel comando.

1
bash vars non supporta tanti tipi come Python, ma ha string, integer e due tipi di array ("indicizzato" / tradizionale e "associativo" che è simile a awk array, perl hash o Python dict). Altre conchiglie variano; solo la stringa è portatile .
dave_thompson_085,

7

La risposta accettata implica questo, ma vorrei rendere esplicita la connessione ai builtin della shell:

Come già accennato, exportrenderà disponibile una variabile sia per la shell che per i bambini. Se nonexport viene utilizzata, la variabile sarà disponibile solo nella shell e solo i builtin della shell potranno accedervi.

Questo è,

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

3

Ecco un altro esempio:

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}"'  

Solo usando export VARTEST il valore di VARTEST è disponibile in sudo bash -c '...'!

Per ulteriori esempi vedere:


3

Due dei creatori di UNIX, Brian Kernighan e Rob Pike, lo spiegano nel loro libro "L'ambiente di programmazione UNIX". Google per il titolo e troverai facilmente una versione pdf.

Indirizzano le variabili della shell nella sezione 3.6 e si concentrano sull'uso del exportcomando alla fine di quella sezione:

Quando si desidera rendere accessibile il valore di una variabile nelle sotto-shell, è necessario utilizzare il comando di esportazione della shell. (Potresti pensare al motivo per cui non c'è modo di esportare il valore di una variabile da una sotto-shell al suo genitore).


2

Solo per mostrare la differenza tra una variabile esportata nell'ambiente (env) e una variabile non esportata non nell'ambiente:

Se lo faccio:

$ MYNAME=Fred
$ export OURNAME=Jim

quindi solo $ OURNAME appare nell'ambiente. La variabile $ MYNAME non è nell'ambiente.

$ env | grep NAME
OURNAME=Jim

ma la variabile $ MYNAME esiste nella shell

$ echo $MYNAME
Fred

1

Per impostazione predefinita, le variabili create all'interno di uno script sono disponibili solo per la shell corrente; i processi figlio (sotto-shell) non avranno accesso ai valori che sono stati impostati o modificati. Consentire ai processi figlio di vedere i valori, richiede l'uso del comando export.


0

Sebbene non sia esplicitamente menzionato nella discussione, NON è necessario utilizzare l'esportazione quando si genera una subshell da dentro bash poiché tutte le variabili vengono copiate nel processo figlio.


Spiega come ciò che stai dicendo sembra contraddire direttamente le risposte con esempi sopra.
Mike Lippert,

Questo è il modo giusto se non vuoi che le variabili vengano esportate a livello globale ma disponibili solo per il sottoprocesso! Grazie.
jtblin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.