Quando ti accorgi di digitare la stessa sequenza di comandi per la terza volta, è il momento di scrivere uno script. Uno script Bash non è altro che un file di testo con dentro i comandi che scriveresti a mano, più qualche costrutto per prendere decisioni e ripetere operazioni. Non serve essere programmatori: bastano poche regole, e soprattutto qualche abitudine prudente.
Il primo script
#!/usr/bin/env bash
echo "Spazio libero sul disco principale:"
df -h /
La prima riga, detta shebang, dice al sistema quale interprete usare. Salvato il file come spazio.sh, lo si rende eseguibile con chmod +x spazio.sh e lo si avvia con ./spazio.sh. Il ./ serve perché la cartella corrente, per sicurezza, non fa parte dei percorsi in cui la shell cerca i comandi.
Variabili e virgolette
cartella="/home/anna/Documenti"
data=$(date +%Y-%m-%d)
echo "Backup di $cartella del $data"
Due regole evitano molti errori. La prima: nessuno spazio attorno al segno uguale; cartella = "..." viene interpretato come un comando chiamato cartella. La seconda: metti sempre le variabili tra virgolette doppie quando le usi. Se una variabile contiene Foto vacanze, senza virgolette rm $file diventa rm Foto vacanze e tenta di cancellare due file distinti. Con rm "$file" il nome resta intero.
La sintassi $(comando) inserisce l'output di un comando in una variabile. Le virgolette singole, invece, impediscono qualsiasi sostituzione: echo '$data' stampa letteralmente $data.
Argomenti dello script
Gli argomenti passati sulla riga di comando sono disponibili come $1, $2 e così via; $# ne indica il numero e "$@" li contiene tutti, ognuno correttamente separato. Un controllo all'inizio rende lo script più amichevole:
if [ "$#" -ne 1 ]; then
echo "Uso: $0 cartella" >&2
exit 1
fi
Condizioni con if
La struttura è if ... then ... else ... fi. Le verifiche più comuni:
| Test | Vero se |
|---|---|
[ -f "$x" ] |
$x è un file esistente |
[ -d "$x" ] |
$x è una cartella esistente |
[ -z "$x" ] |
la stringa è vuota |
[ "$a" = "$b" ] |
le stringhe sono uguali |
[ "$n" -gt 10 ] |
il numero è maggiore di 10 |
Per i confronti numerici si usano -eq, -ne, -lt, -le, -gt, -ge, non i simboli < e >, che dentro le parentesi quadre sarebbero interpretati come redirezioni. Bash offre anche le doppie parentesi [[ ... ]], più tolleranti con le variabili vuote.
Cicli for e while
Il ciclo for ripete un blocco per ogni elemento di un elenco:
for foto in *.jpg; do
echo "Elaboro $foto"
cp -- "$foto" "archivio/$foto"
done
Il doppio trattino -- dice al comando che gli argomenti successivi non sono opzioni: protegge da file il cui nome inizia con un trattino.
Il ciclo while ripete finché una condizione è vera. L'uso più tipico è leggere un file riga per riga:
while IFS= read -r riga; do
echo "Server: $riga"
done < server.txt
IFS= e -r evitano che spazi iniziali e barre rovesciate vengano alterati: è la forma da usare quasi sempre.
Codici di uscita
Ogni comando termina con un numero: 0 significa successo, qualunque altro valore un errore. La variabile $? contiene il codice dell'ultimo comando. Anche lo script dovrebbe uscire con exit 0 quando va tutto bene e con un valore diverso quando qualcosa fallisce: così può essere usato in catene con && o in un sistema di pianificazione che segnala gli errori.
Le tre opzioni di sicurezza
Molti script partono con questa riga dopo lo shebang:
set -euo pipefail
-einterrompe lo script al primo comando che fallisce, invece di proseguire su uno stato inconsistente;-uconsidera un errore l'uso di una variabile non definita, evitando che un refuso produca un percorso vuoto;-o pipefailfa fallire una pipe se fallisce uno qualsiasi dei comandi, non solo l'ultimo.
L'utilità di -u è evidente con un esempio: se per errore scrivi rm -rf "$CARTELA/" invece di $CARTELLA, senza -u la variabile è vuota e il comando diventa rm -rf "/". Con -u lo script si ferma prima.
Funzioni e leggibilità
Le funzioni raggruppano operazioni ripetute:
log() {
echo "$(date '+%H:%M:%S') $*"
}
log "Inizio copia"
Commenti con #, nomi di variabili chiari e funzioni brevi rendono lo script comprensibile anche dopo mesi. Prima di metterlo in uso, lo strumento ShellCheck analizza il codice e segnala virgolette mancanti, test scritti male e altri errori comuni: è uno dei modi migliori per imparare.
Quando passare a un altro linguaggio
Bash è ideale per orchestrare comandi e manipolare file. Quando lo script supera qualche centinaio di righe, deve gestire strutture dati complesse o fare calcoli non banali, conviene passare a un linguaggio come Python, che offre gestione degli errori e librerie più adatte.
In sintesi
- Uno script inizia con lo shebang, si rende eseguibile con
chmod +xe si avvia con./. - Nessuno spazio attorno a
=e variabili sempre tra virgolette doppie. - Usa
-eq,-gte simili per i numeri;while IFS= read -rper leggere file riga per riga. set -euo pipefailferma lo script agli errori e alle variabili non definite.- Controlla gli script con ShellCheck e passa a Python quando la logica si complica.