Prima o poi capita a tutti: installi un programma, lo lanci dal terminale e la shell risponde «command not found», anche se il file è lì. Oppure segui una guida che dice di «aggiungere una riga al bashrc» senza spiegare perché. Dietro entrambi i casi c'è lo stesso meccanismo, quello delle variabili d'ambiente, ed è uno dei concetti che rendono più semplice tutto il resto.
Che cos'è una variabile d'ambiente
Ogni processo riceve, al momento dell'avvio, un piccolo insieme di coppie nome-valore: l'ambiente. I programmi le leggono per sapere, per esempio, qual è la cartella home dell'utente, che lingua usare o quale editor aprire. Alcune delle più comuni:
| Variabile | Contenuto |
|---|---|
HOME |
la cartella personale dell'utente |
USER |
il nome dell'utente |
PATH |
le cartelle in cui cercare i comandi |
LANG |
lingua e formato regionale |
EDITOR |
l'editor predefinito per i programmi che ne aprono uno |
SHELL |
la shell di accesso |
Per vederle tutte si usa env o printenv; per una sola, echo $HOME.
Variabili della shell e variabili esportate
Nella shell puoi creare una variabile con un'assegnazione, senza spazi attorno all'uguale:
PROGETTO=/srv/sito
echo $PROGETTO
Questa variabile però resta nella shell corrente. Se lanci un programma o uno script, non la vede. Per passarla ai processi figli bisogna esportarla:
export PROGETTO=/srv/sito
È una distinzione che spiega molti comportamenti misteriosi: uno script che «non trova» una variabile appena impostata, di solito, la sta cercando senza che sia stata esportata. Va ricordato anche che l'ambiente si eredita solo verso il basso: un processo figlio non può modificare l'ambiente del genitore. Per questo uno script che fa export non cambia il terminale da cui l'hai lanciato, a meno di eseguirlo con source script.sh.
Per impostare una variabile solo per un singolo comando c'è una forma compatta:
LANG=C ls -l
Utile per esempio per ottenere messaggi in inglese, più facili da cercare quando si diagnostica un errore.
Come funziona il PATH
Quando scrivi ls, la shell non sa dove si trovi quel programma. Guarda la variabile PATH, un elenco di cartelle separate da due punti:
echo $PATH
/usr/local/bin:/usr/bin:/bin:/home/anna/.local/bin
e le prova nell'ordine, fermandosi alla prima che contiene un file eseguibile con quel nome. Ne derivano due conseguenze pratiche:
- un programma che sta in una cartella non elencata non si trova, e va lanciato con il percorso completo, come
./script.sho/opt/tool/bin/tool; - se due cartelle contengono un comando con lo stesso nome, vince quella che viene prima.
Per sapere quale versione di un comando viene usata davvero si usano type nome o command -v nome. Il primo indica anche se si tratta di un alias o di una funzione della shell.
Per aggiungere una cartella al PATH si mette in fondo, o in testa se deve avere la precedenza:
export PATH="$HOME/.local/bin:$PATH"
L'errore classico è scrivere PATH=$HOME/bin senza il :$PATH finale: la shell perde tutte le altre cartelle e smette di trovare perfino ls. Se succede, nella sessione corrente si rimedia con export PATH=/usr/bin:/bin e poi si corregge il file.
.bashrc, .profile e gli altri
Le variabili impostate a mano durano fino alla chiusura del terminale. Per renderle stabili si scrivono in un file letto all'avvio della shell. Quale file, dipende dal tipo di shell:
- shell di login (accesso da console o via SSH): Bash legge
~/.bash_profileoppure, se non esiste,~/.profile; - shell interattiva non di login (un nuovo terminale nel desktop): Bash legge
~/.bashrc.
Su molte distribuzioni ~/.profile include a sua volta ~/.bashrc, così le impostazioni valgono ovunque. Una suddivisione ragionevole: variabili d'ambiente come PATH ed EDITOR in ~/.profile, alias, funzioni e aspetto del prompt in ~/.bashrc. Su macOS la shell predefinita è da anni zsh, che usa ~/.zshrc e ~/.zprofile.
Dopo una modifica non serve chiudere il terminale:
source ~/.bashrc
Le impostazioni valide per tutti gli utenti stanno in /etc/profile, /etc/profile.d/ e /etc/environment.
Alias utili
Gli alias abbreviano comandi lunghi o aggiungono opzioni di sicurezza:
alias ll='ls -lh'
alias rm='rm -i'
alias aggiorna='sudo apt update && sudo apt upgrade'
Nel mio lavoro preferisco alias pochi e chiari: un terminale personalizzato all'eccesso diventa difficile da usare quando ti trovi su una macchina che non è la tua, dove nessuno di quegli alias esiste.
Segreti nelle variabili: con cautela
È comune passare chiavi di accesso ai programmi tramite variabili d'ambiente. Va bene, ma con attenzione: le variabili esportate sono visibili ai processi figli e, per lo stesso utente, leggibili in /proc/<PID>/environ. Non vanno scritte in .bashrc se il file finisce in un repository o in un backup condiviso, e un comando come export TOKEN=... digitato a mano resta nella cronologia della shell.
In sintesi
- L'ambiente è un insieme di variabili che ogni processo eredita dal genitore.
- Senza
exportuna variabile resta nella shell corrente e gli script non la vedono. - Il PATH si legge nell'ordine; per aggiungere una cartella si mantiene sempre
:$PATH. ~/.profileper le variabili,~/.bashrcper alias e prompt; su macOS~/.zshrc.typeecommand -vrivelano quale comando viene eseguito davvero.