Questa è una vecchia domanda, ma nessuna delle risposte qui parla dell'uso di set -e
aka set -o errexit
negli script di gestione dei pacchetti Debian. L'uso di questa opzione è obbligatorio in questi script, secondo la politica Debian; l'intento è apparentemente quello di evitare qualsiasi possibilità di una condizione di errore non gestita.
Ciò significa in pratica che devi capire in quali condizioni i comandi che esegui potrebbero restituire un errore e gestirli in modo esplicito.
I gotcha comuni sono ad es. diff
(Restituisce un errore in caso di differenza) e grep
(restituisce un errore in assenza di corrispondenza). È possibile evitare gli errori con la gestione esplicita:
diff this that ||
echo "$0: there was a difference" >&2
grep cat food ||
echo "$0: no cat in the food" >&2
(Notare anche come ci prendiamo cura di includere il nome dello script corrente nel messaggio e scrivere messaggi diagnostici in errore standard invece che in output standard.)
Se nessuna gestione esplicita è davvero necessaria o utile, non fare esplicitamente nulla:
diff this that || true
grep cat food || :
(L'uso del :
comando no-op della shell è leggermente oscuro, ma abbastanza comune.)
Solo per ribadire,
something || other
è una scorciatoia per
if something; then
: nothing
else
other
fi
cioè diciamo esplicitamente che other
dovrebbe essere eseguito se e solo se something
fallisce. Il longhand if
(e altre dichiarazioni di controllo del flusso della shell comewhile
, until
) è anche un modo valido per gestire un errore (in effetti, se non lo fosse, gli script di shell con set -e
non potrebbero mai contenere istruzioni di controllo del flusso!)
Inoltre, solo per essere espliciti, in assenza di un gestore come questo, set -e
farebbe fallire immediatamente l'intero script con un errore sediff
trovasse una differenza o se grep
non trovasse una corrispondenza.
D'altra parte, alcuni comandi non producono uno stato di uscita dell'errore quando lo si desidera. Comuni comunemente problematici sono find
(lo stato di uscita non riflette se i file sono stati effettivamente trovati) e sed
(lo stato di uscita non rivelerà se lo script ha ricevuto input o effettivamente eseguito correttamente i comandi). Una semplice protezione in alcuni scenari è convogliare un comando che urla se non c'è output:
find things | grep .
sed -e 's/o/me/' stuff | grep ^
Va notato che lo stato di uscita di una pipeline è lo stato di uscita dell'ultimo comando in quella pipeline. Quindi i comandi precedenti in realtà mascherano completamente lo stato di find
e sed
, e ti dicono solo se alla grep
fine ci sono riusciti.
(Bash, ovviamente, l'ha fatto set -o pipefail
; ma gli script di pacchetti Debian non possono usare le funzionalità di Bash. La politica impone fermamente l'uso di POSIX sh
per questi script, anche se non è sempre stato così).
In molte situazioni, questo è qualcosa a cui prestare attenzione separatamente quando si codifica in modo difensivo. A volte è necessario, ad esempio, passare attraverso un file temporaneo in modo da poter vedere se il comando che ha prodotto quell'output è terminato correttamente, anche quando il linguaggio e la convenienza ti indirizzerebbero altrimenti a utilizzare una pipeline di shell.