Come abbiamo visto nel caso dei costrutti condizionali, al termine della valutazione di un comando viene ritornato un valore intero non negativo, chiamato exit status, al processo chiamante.
Per convenzione, si usa ritornare 0 se l'esecuzione è terminata con successo (nel caso di un comando if
, questo corrisponde al valore vero), oppure un valore intero positivo nel caso essa sia fallita con un errore: questo permette di definire vari codici di errore utilizzando diversi numeri positivi, così da distinguere il tipo di fallimento avvenuto.
Uno script Bash ritorna un valore al processo chiamante tramite il comando built-in exit; il comando exit 4
, perciò, terminerà lo script (i comandi specificati dopo di esso non saranno mai eseguiti) e ritornerà un exit status di valore 4, indicando un certo tipo di errore. Omettendo l'exit status nel comando exit
, oppure omettendo totalmente il comando, lo script ritorna l'exit status dell'ultimo comando eseguito all'interno di esso.
AND (&&) e OR (||)
Un modo molto pratico e frequente di utilizzare gli exit status in Bash è tramite gli operatori and (&&
) e or (||
). Quando due comandi vengono separati da &&
, il comando di destra viene eseguito solamente se il comando di sinistra termina con successo; viceversa, quando vengono separati da ||
, il secondo comando viene eseguito solo in caso di fallimento del primo.
Ad esempio, supponiamo di voler eliminare il file esempio.txt
e creare un nuovo file con lo stesso nome. Possiamo eliminarlo utilizzando il comando rm
e crearlo di nuovo utilizzando touch
; perciò potremmo scrivere in sequenza:
rm esempio.txt
touch esempio.txt
Ma nel caso in cui il comando di cancellazione fallisca, potremmo non volere che lo script procedesse con il secondo comando; possiamo perciò scrivere quanto segue:
rm esempio.txt && touch esempio.txt
NOT (!)
Un terzo operando booleano, certamente meno utilizzato dei precedenti, è not (!
), che inverte il valore di exit status di un comando; ad esempio, !rm esempio.txt
è equivalente ad eseguire rm esempio.txt
, ma ne indicherà l'avvenuto successo se il comando rm
è fallito, e viceversa. L'utilizzo di questo costrutto diventa più sostanziale se unito ai precedenti e a quelli supportati dal comando test
, come abbiamo visto nella lezione 7.
Per concludere, l'exit status dell'ultimo comando eseguito è disponibile anche nella variabile built-in $?
; accedervi può essere utile nel caso si voglia distinguere fra diversi codici di errore (magari utilizzando il costrutto switch
): ad esempio, il comando grep
(che cerca in un file le righe corrispondenti a un pattern specificato) ritorna 0 se trova un match, 1 in caso contrario, e 2 se è avvenuto un errore.