Risoluzione degli errori di sintassi comuni in Bash: una guida pratica
Correggi gli errori di sintassi comuni in Bash con esempi per virgolette, parentesi, variabili, reindirizzamenti e problemi di ricerca dei comandi.
Risoluzione degli errori di sintassi comuni in Bash: una guida pratica
Gli errori di sintassi in Bash di solito derivano da piccole sviste: una virgoletta mancante, una parentesi errata, un reindirizzamento fuori posto o una variabile che si è espansa in qualcosa di inaspettato. Quando il tuo script Bash si ferma con syntax error near unexpected token, inizia controllando la riga prima di quella segnalata da Bash, poi esegui lo script con un controllo di sintassi.
Usa questo controllo rapido prima di eseguire uno script modificato su un server:
bash -n script.sh
bash -n analizza il file senza eseguire comandi. Non catturerà tutti i bug logici, ma rileva molte virgolette spezzate, istruzioni fi mancanti e cicli malformati.
Virgolette mancanti
Le virgolette non chiuse sono uno dei modi più veloci per confondere il parser.
nome="deploy
printf 'Distribuzione di %s\n' "$nome"
Bash continua a leggere le righe successive perché sta ancora cercando la " di chiusura. Risolvi chiudendo la virgoletta e citando le espansioni di variabili che potrebbero contenere spazi:
nome="deploy"
printf 'Distribuzione di %s\n' "$nome"
Usa le virgolette doppie quando vuoi che le variabili si espandano. Usa le virgolette singole quando vuoi testo letterale:
printf 'HOME rimane letterale: $HOME\n'
printf "HOME si espande: %s\n" "$HOME"
Blocchi if, for e while errati
Ogni comando composto necessita della sua parola chiave di chiusura. Se manca, spesso l'errore viene segnalato vicino alla fine del file.
if systemctl is-active --quiet nginx; then
echo "nginx è in esecuzione"
# manca fi
Versione corretta:
if systemctl is-active --quiet nginx; then
echo "nginx è in esecuzione"
fi
Lo stesso schema si applica a cicli e istruzioni case:
for host in web1 web2 web3; do
ssh "$host" uptime
done
case "$env" in
prod) echo "produzione" ;;
dev) echo "sviluppo" ;;
*) echo "sconosciuto" ;;
esac
Errori con parentesi e test
Il comando [ è un vero comando, quindi necessita di spazi attorno ai suoi argomenti e prima della parentesi di chiusura.
Errato:
if [$count -gt 5]; then
echo "troppi"
fi
Corretto:
if [ "$count" -gt 5 ]; then
echo "troppi"
fi
Per script specifici di Bash, [[ ... ]] è spesso più sicuro per i test sulle stringhe perché gestisce le variabili vuote in modo più elegante e supporta il pattern matching:
if [[ "$file" == *.log ]]; then
gzip "$file"
fi
Usa operatori numerici per i numeri e operatori stringa per il testo:
[[ "$status" == "pronto" ]] # confronto stringhe
[[ "$retries" -lt 3 ]] # confronto numerico
Problemi di espansione delle variabili
Un errore comune è aggiungere spazi attorno a = durante l'assegnazione. Bash lo tratta come un comando invece che come un'assegnazione di variabile.
Errato:
backup_dir = /var/backups
Corretto:
backup_dir=/var/backups
Usa le parentesi graffe quando il nome della variabile tocca altro testo:
servizio="nginx"
log="/var/log/${servizio}.log"
Senza parentesi graffe, Bash potrebbe leggere un nome di variabile più lungo di quanto intendessi.
Errori command not found
command not found non è sempre un errore di sintassi. Di solito significa che Bash non ha trovato un eseguibile con quel nome.
Controlla prima gli errori di battitura:
systemctl status nginx
Poi verifica se il comando esiste ed è in PATH:
command -v systemctl
printf '%s\n' "$PATH"
Se lo script viene eseguito con cron, systemd o un job CI, PATH potrebbe essere più corto rispetto alla tua shell interattiva. Usa percorsi assoluti per i comandi critici o imposta PATH all'inizio dello script:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export PATH
Errori di reindirizzamento e pipe
L'ordine di reindirizzamento è importante. Questo comando scrive stdout su app.log e poi invia stderr nello stesso posto:
./deploy.sh >app.log 2>&1
Questo è diverso perché stderr viene copiato nel vecchio stdout prima che stdout venga reindirizzato:
./deploy.sh 2>&1 >app.log
Per le pipeline, ricorda che Bash normalmente restituisce il codice di uscita dell'ultimo comando. Usa pipefail quando un comando fallito nel mezzo dovrebbe far fallire l'intera pipeline:
set -o pipefail
kubectl get pods | grep CrashLoopBackOff
Un flusso di debug pratico
Inizia con un controllo di sintassi:
bash -n script.sh
Esegui con tracciamento quando la sintassi è valida ma il comportamento è sbagliato:
bash -x script.sh
Per script di produzione più sicuri, aggiungi la modalità rigorosa deliberatamente e testa lo script dopo ogni modifica:
set -euo pipefail
set -e esce su molti fallimenti di comandi, set -u tratta le variabili non impostate come errori e pipefail cattura i fallimenti all'interno delle pipeline. Queste opzioni sono utili, ma possono cambiare il comportamento dello script, quindi abilitale intenzionalmente invece di inserirle in uno script vecchio senza test.
Conclusione
La maggior parte degli errori di sintassi in Bash diventano semplici una volta che controlli virgolette, parole chiave di chiusura, spaziatura delle parentesi, assegnazioni di variabili e reindirizzamenti in quest'ordine. Tieni bash -n e bash -x nel tuo flusso di lavoro normale e testa gli script con la stessa shell e ambiente che verranno utilizzati in produzione.