Molti programmi leggono le loro impostazioni da variabili d'ambiente: PATH dice dove cercare i comandi, EDITOR quale editor aprire, LANG in che lingua parlare. Con export si creano queste variabili e si fa in modo che i programmi lanciati dalla shell le vedano.
Cos'è
Una variabile è un nome a cui si associa un valore: NOME=Enzo. Nella shell esistono però due tipi di variabili:
- le variabili di shell (locali), che vede solo la shell stessa;
- le variabili d'ambiente (environment), che vengono copiate in ogni programma o script che la shell avvia.
export è il comando interno della shell (come cd e alias) che trasforma una variabile di shell in una variabile d'ambiente, "esportandola" ai processi figli. Gli esempi sono per bash.
Cosa fa
Segna una variabile come esportabile: da quel momento, ogni comando che lanci riceve una copia del suo valore. La copia va solo verso il basso: i processi figli ereditano le variabili, ma ciò che un programma cambia al suo interno non risale alla shell che l'ha lanciato, e non arriva agli altri terminali già aperti.
Come si usa
$ export NOME=valore
$ export NOME
$ exportLe variabili si scrivono di solito in maiuscolo, con lettere, cifre e il trattino basso, e senza spazi attorno al segno =. Si leggono mettendo un $ davanti al nome.
Esempio 1: variabile di shell e variabile d'ambiente
$ SALUTO="Ciao dal terminale"
$ echo "$SALUTO"
Ciao dal terminale
$ bash -c 'echo "Il figlio vede: [$SALUTO]"'
Il figlio vede: []
$ export SALUTO
$ bash -c 'echo "Il figlio vede: [$SALUTO]"'
Il figlio vede: [Ciao dal terminale]Qui la variabile esiste in shell, ma un programma figlio (una nuova bash) non la vede finché non viene esportata. Dopo export SALUTO il figlio riceve il valore. Si può anche definire ed esportare in un solo passaggio: export SALUTO="Ciao".
Esempio 2: vedere le variabili d'ambiente
$ printenv HOME
/home/enzo
$ printenv | head -n 4
SHELL=/bin/bash
LANG=it_IT.UTF-8
HOME=/home/enzo
USER=enzo
$ env | grep -i '^LANG'
LANG=it_IT.UTF-8
$ export -p | tail -n 2
declare -x SALUTO="Ciao dal terminale"
declare -x SHELL="/bin/bash"
$ echo "$USER lavora in $PWD con $SHELL"
enzo lavora in /home/enzo con /bin/bashprintenv e env mostrano le variabili d'ambiente (printenv NOME ne stampa una sola). export -p (o export senza argomenti) le elenca in forma di comandi declare -x. Il comando set, invece, mostra tutte le variabili della shell, anche quelle non esportate, e le funzioni: l'elenco è lungo. Alcune variabili comuni: HOME, USER, SHELL, PWD, PATH, LANG, EDITOR, TERM.
Esempio 3: il PATH, la variabile più importante
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$ mkdir -p ~/bin
$ printf '#!/bin/bash\necho "Ciao da mio-comando"\n' > ~/bin/mio-comando
$ chmod +x ~/bin/mio-comando
$ mio-comando
bash: mio-comando: comando non trovato
$ export PATH="$HOME/bin:$PATH"
$ mio-comando
Ciao da mio-comandoPATH è un elenco di cartelle, separate da due punti, in cui la shell cerca i comandi che scrivi. Per usare i propri programmi senza scrivere il percorso completo si aggiunge una cartella (qui ~/bin) davanti a quelle esistenti, mantenendo il resto con :$PATH. Per sapere dove si trova un comando: command -v nome o type nome. Se si dimentica di rimettere $PATH alla fine, la variabile contiene solo la nuova cartella e anche ls sparisce (vedi più avanti).
Esempio 4: una variabile per un solo comando
$ LANG=C date
Mon Oct 26 07:41:03 CET 2026
$ date
lun 26 ott 2026, 07:41:09, CET
$ TZ=America/New_York date
Mon Oct 26 02:41:15 EDT 2026
$ echo "[$LANG]"
[it_IT.UTF-8]Scrivendo VARIABILE=valore comando sulla stessa riga, la variabile vale solo per quel comando (senza export e senza lasciare tracce nella shell). Qui, LANG=C mostra la data in formato neutro, e TZ in un altro fuso orario. È comodo per prove e per forzare il comportamento di un programma una volta sola.
Esempio 5: l'editor e la lingua di sistema
$ export EDITOR=nano
$ export VISUAL=nano
$ crontab -e
$ export LC_ALL=C
$ ls | sort
$ unset LC_ALLEDITOR (e VISUAL) dice a crontab -e, git commit, visudo e molti altri quale editor usare, per esempio nano. LC_ALL=C imposta la lingua "neutra" e un ordinamento semplice, basato sui codici dei caratteri: utile negli script, perché sort e altri comandi danno gli stessi risultati su ogni computer (con sort le maiuscole vengono prima delle minuscole). unset elimina una variabile.
Esempio 6: rendere le variabili permanenti
$ nano ~/.bashrc
export EDITOR=nano
export PATH="$HOME/bin:$PATH"
export HISTTIMEFORMAT="%F %T "
$ source ~/.bashrc
$ echo $EDITOR
nanoUna variabile esportata nel terminale sparisce alla chiusura. Per tenerla, si scrive la riga export in un file che la shell legge all'avvio: ~/.bashrc per i terminali interattivi (con source si rilegge nella sessione aperta), ~/.profile o ~/.bash_profile per i login (come una connessione ssh o una sessione sulla console). Su Debian e Ubuntu il file ~/.profile carica ~/.bashrc, quindi in genere basta il secondo. Per tutti gli utenti, in modo semplice, c'è /etc/environment, con righe NOME=valore (senza export, senza $ e senza espansioni) che si modifica con sudo nano; oppure un file .sh in /etc/profile.d/.
Esempio 7: variabili e sudo
$ export PROGETTO=blog
$ sudo bash -c 'echo "[$PROGETTO]"'
[]
$ sudo PROGETTO=blog bash -c 'echo "[$PROGETTO]"'
[blog]
$ sudo -E bash -c 'echo "[$PROGETTO]"'
[blog]
$ sudo env | grep PROGETTOsudo per sicurezza ripulisce l'ambiente: le tue variabili non passano al comando eseguito con privilegi, tranne poche (HOME e altre) decise nella configurazione. Per passarne una, si scrive sudo VARIABILE=valore comando. Con sudo -E si chiede di conservare l'intero ambiente, ma può essere vietato dalla configurazione di sudoers, e non è consigliato. Non aspettarti quindi che un sudo comando veda il tuo PATH o il tuo EDITOR.
Esempio 8: segreti e chiavi
$ read -rs -p "Token API: " API_TOKEN; echo
Token API:
$ export API_TOKEN
$ curl -s -H "Authorization: Bearer $API_TOKEN" https://example.org/api/dati
$ unset API_TOKENLe variabili d'ambiente sono comode per passare chiavi e token ai programmi (curl, script, strumenti da riga di comando) senza scriverle nei file. Se però scrivi export API_TOKEN=abc123, il comando finisce nella cronologia (vedi l'articolo su history). Con read -rs la shell legge il valore senza mostrarlo e senza salvarlo nella cronologia: -s nasconde ciò che digiti, -r non interpreta le barre inverse, -p mostra il messaggio. Al termine, unset toglie la variabile. Ricorda che l'ambiente di un programma è leggibile dallo stesso utente (con ps e o in /proc/PID/environ), e dall'amministratore: non è un caveau.
Esempio 9: caricare le variabili da un file .env
$ cat .env
DB_HOST=localhost
DB_NAME=blog
APP_ENV=produzione
$ set -a
$ source .env
$ set +a
$ printenv | grep -E '^(DB_|APP_)'
DB_HOST=localhost
DB_NAME=blog
APP_ENV=produzioneMolte applicazioni (anche quelle in docker compose) tengono le impostazioni in un file .env, con una riga NOME=valore per variabile. Per caricarle nella shell ed esportarle tutte in una volta, si attiva set -a (allexport: da qui in poi ogni variabile definita viene esportata), si legge il file con source e si disattiva con set +a. Il file va protetto (chmod 600 .env) e non va incluso nei repository pubblici. Contenuto con spazi o caratteri speciali richiede le virgolette: TITOLO="Il mio blog".
Esempio 10: l'ambiente dei processi non risale
$ cat imposta.sh
#!/bin/bash
export PROVA="impostata dallo script"
echo "Nello script: $PROVA"
$ chmod +x imposta.sh
$ ./imposta.sh
Nello script: impostata dallo script
$ echo "Nella shell: [$PROVA]"
Nella shell: []
$ source imposta.sh
Nello script: impostata dallo script
$ echo "Nella shell: [$PROVA]"
Nella shell: [impostata dallo script]Uno script viene eseguito in un processo figlio: tutto quello che imposta (variabili, cartella corrente) sparisce quando termina. Se invece lo si legge con source (o con . imposta.sh), le istruzioni vengono eseguite dentro la shell corrente, e le variabili restano. È il motivo per cui gli script di "attivazione" (come quelli degli ambienti virtuali di Python) vanno richiamati con source.
Esempio 11: servizi e cron non leggono ~/.bashrc
$ crontab -l
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=""
0 3 * * * /home/enzo/bin/backup.sh
$ systemctl cat mio-script | grep -i environment
Environment=APP_ENV=produzione
EnvironmentFile=/etc/mio-script.envI lavori di cron e i servizi di systemd non passano da ~/.bashrc: hanno un ambiente quasi vuoto. In crontab le variabili si scrivono in cima alla tabella; nelle unità di systemd si usano Environment= (una variabile) e EnvironmentFile= (un file con righe NOME=valore). Dopo una modifica serve systemctl daemon-reload e il riavvio del servizio. Se uno script funziona a mano ma non da cron, la causa è quasi sempre una variabile (spesso PATH) mancante.
Esempio 12: negli script, con valori predefiniti e controlli
#!/bin/bash
export LC_ALL=C
DESTINAZIONE="${BACKUP_DIR:-$HOME/backup}"
: "${API_TOKEN:?Variabile API_TOKEN non impostata}"
mkdir -p "$DESTINAZIONE"
echo "Backup in: $DESTINAZIONE"
curl -fsS -H "Authorization: Bearer $API_TOKEN" \
https://example.org/api/export -o "$DESTINAZIONE/export.json"Lo script usa tre costrutti utili. export LC_ALL=C rende i comandi prevedibili. ${BACKUP_DIR:-$HOME/backup} usa il valore della variabile se è impostata e, altrimenti, quello predefinito dopo :-. : "${API_TOKEN:?messaggio}" interrompe lo script con un messaggio d'errore se la variabile manca o è vuota (i due punti iniziali sono un comando che non fa nulla, serve a "usare" l'espansione). L'utente lo esegue così: BACKUP_DIR=/mnt/disco ./backup.sh, oppure dopo aver esportato le variabili.
Esempio 13: esportare anche le funzioni
$ saluta() { echo "Ciao, $1"; }
$ printf 'Anna\nMarco\n' | xargs -I{} bash -c 'saluta {}'
bash: riga 1: saluta: comando non trovato
bash: riga 1: saluta: comando non trovato
$ export -f saluta
$ printf 'Anna\nMarco\n' | xargs -I{} bash -c 'saluta {}'
Ciao, Anna
Ciao, MarcoCon l'opzione -f, export esporta una funzione di bash, in modo che la vedano anche i processi figli (come le bash lanciate da xargs o da find -exec). Con export -n nome una variabile smette di essere esportata, ma resta definita nella shell. Questa funzione è specifica di bash: in altre shell non esiste.
Opzioni utili
export NOME=valore: crea ed esporta una variabile;export NOME: esporta una variabile già definita.export/export -p: elenca le variabili esportate.export -n NOME: la rende di nuovo locale alla shell.export -f funzione: esporta una funzione dibash.unset NOME: elimina una variabile (unset -funa funzione).printenv [NOME]/env: mostra l'ambiente (env -i comandolancia un comando con ambiente vuoto).VARIABILE=valore comando: valore valido solo per quel comando.set -a/set +a: esporta automaticamente tutte le variabili definite.readonly NOME=valore: variabile che non si può più modificare.${VAR:-predefinito},${VAR:?messaggio},${VAR:+altro}: valori predefiniti e controlli.
Attenzione a
- Niente spazi attorno al segno uguale:
export NOME = valoreè un errore, perché la shell interpreta tre elementi separati. Si scriveNOME=valore, e con spazi nel valoreNOME="un valore". - Non perdere il vecchio PATH:
export PATH="$HOME/bin"sostituisce tutto l'elenco e il terminale non trova più nélsnénano(cdcontinua a funzionare, perché è interno alla shell). Va scrittoexport PATH="$HOME/bin:$PATH". Se succede, basta chiudere il terminale e aprirne uno nuovo (se la riga è solo nel terminale), oppure correggere il file e usare i percorsi completi, come/usr/bin/nano. - Il
PATHripetuto: aggiungere la stessa cartella in~/.bashrce poi ricaricare il file più volte (source ~/.bashrc) allunga l'elenco con ripetizioni. Non è grave, ma conviene controllare conecho $PATH. - Mai
.o una cartella vuota nelPATH: far cercare i comandi nella cartella corrente permette a un file malevolo di sostituirsi a un comando normale. Una voce vuota (come inPATH=:/usr/bin) vale come "cartella corrente". - Le virgolette contano: tra apici doppi (
"$HOME/bin") la variabile viene sostituita; tra apici singoli ('$HOME/bin') il testo resta così com'è, e il percorso ottenuto non esiste. Quasi sempre vanno usati gli apici doppi, anche quando si legge una variabile (echo "$NOME"), per non rompere i valori con spazi. - Vale solo per quel terminale e per i suoi figli: non è una configurazione globale. Una variabile esportata in una finestra non compare in quelle già aperte, né in
cron, né in una connessionesshsuccessiva, a meno che sia scritta in un file di avvio. sudoripulisce l'ambiente: ciò che esporti non è visibile al comando lanciato consudo. Passa le variabili necessarie consudo VARIABILE=valore comando.- Segreti nell'ambiente: non scrivere password e token direttamente in
export, perché restano nella cronologia; evita di stamparli (envoprintenvin un registro o in una richiesta di assistenza possono rivelarli) e non lasciarli in file di avvio leggibili da tutti. - Variabili e shell diverse:
export NOME=valorefunziona inbashezsh; infishsi usaset -x NOME valore. I file di avvio cambiano (~/.zshrc,~/.config/fish/config.fish). - Nomi riservati: non riusare nomi come
PATH,HOME,USER,SHELLoIFSper scopi diversi, e non iniziare i nomi delle tue variabili con un numero. Nelle variabili degli script, i nomi in minuscolo riducono il rischio di sovrapposizioni con quelle d'ambiente. - Un'applicazione grafica può non leggere
~/.bashrc: i programmi lanciati dal menu del desktop ereditano l'ambiente della sessione grafica, non quello del terminale. Per quelle variabili serve~/.profile(da riavviare la sessione) o/etc/environment.
Riepilogo
| Comando | Cosa fa |
|---|---|
NOME=valore | Crea una variabile di shell (non esportata) |
export NOME=valore | Crea ed esporta una variabile d'ambiente |
export NOME | Esporta una variabile già definita |
echo "$NOME" | Mostra il valore di una variabile |
printenv / env | Elenca le variabili d'ambiente |
export -p | Elenca le variabili esportate come comandi |
unset NOME | Elimina una variabile |
export -n NOME | Smette di esportare la variabile |
NOME=valore comando | Valore valido solo per quel comando |
export PATH="$HOME/bin:$PATH" | Aggiunge una cartella al PATH |
sudo NOME=valore comando | Passa una variabile a un comando con sudo |
read -rs -p "Token: " NOME | Legge un valore riservato senza mostrarlo |
set -a; source .env; set +a | Carica ed esporta le variabili di un file |
export -f funzione | Esporta una funzione di bash |
source ~/.bashrc | Rilegge i file di configurazione |