To stare pytanie, ale żadna z odpowiedzi tutaj nie omawia użycia set -e
aka set -o errexit
w skryptach obsługujących pakiety Debiana. Użycie tej opcji jest obowiązkowe w tych skryptach, zgodnie z polityką Debiana; celem jest najwyraźniej uniknięcie jakiejkolwiek możliwości wystąpienia nieobsługiwanego błędu.
W praktyce oznacza to, że musisz zrozumieć, w jakich warunkach uruchomione polecenia mogą zwrócić błąd i obsłużyć każdy z tych błędów jawnie.
Typowe gotchas to np. diff
(Zwraca błąd, gdy występuje różnica) i grep
(zwraca błąd, gdy nie ma zgodności). Możesz uniknąć błędów dzięki jawnej obsłudze:
diff this that ||
echo "$0: there was a difference" >&2
grep cat food ||
echo "$0: no cat in the food" >&2
(Zwróć też uwagę, jak staramy się zawrzeć w komunikacie nazwę bieżącego skryptu i pisać komunikaty diagnostyczne na standardowy błąd zamiast na standardowe wyjście).
Jeśli żadna jawna obsługa nie jest naprawdę konieczna ani użyteczna, jawnie nic nie rób:
diff this that || true
grep cat food || :
(Użycie :
polecenia no-op powłoki jest nieco niejasne, ale dość powszechne).
Powtarzam,
something || other
jest skrótem od
if something; then
: nothing
else
other
fi
tzn. wyraźnie mówimy, że other
powinien być uruchamiany tylko wtedy, gdy się something
nie powiedzie. Długa if
(i inne instrukcje kontroli przepływu w powłoce, takie jak while
, until
) jest również prawidłowym sposobem obsługi błędu (w rzeczywistości, gdyby tak nie było, skrypty powłoki z set -e
nigdy nie mogłyby zawierać instrukcji kontroli przepływu!)
A także, mówiąc wprost, w przypadku braku takiego programu obsługi, set -e
cały skrypt natychmiast przestanie działać z błędem, jeśli diff
znajdzie różnicę lub grep
nie znajdzie dopasowania.
Z drugiej strony niektóre polecenia nie generują błędu wyjścia, gdy tego chcesz. Powszechnie problematycznymi poleceniami są find
(status wyjścia nie odzwierciedla, czy pliki zostały faktycznie znalezione) i sed
(status wyjścia nie ujawni, czy skrypt otrzymał jakieś dane wejściowe, czy też faktycznie wykonał jakiekolwiek polecenia). Prostą ochroną w niektórych scenariuszach jest potokowanie do polecenia, które krzyczy, jeśli nie ma wyjścia:
find things | grep .
sed -e 's/o/me/' stuff | grep ^
Należy zauważyć, że stanem wyjścia potoku jest status wyjścia ostatniego polecenia w tym potoku. Tak więc powyższe polecenia faktycznie całkowicie maskują status find
i sed
i mówią tylko, czy w grep
końcu się udało.
(Bash oczywiście ma set -o pipefail
; ale skrypty pakietów Debiana nie mogą korzystać z funkcji Bash. Polityka zdecydowanie dyktuje użycie POSIX sh
dla tych skryptów, chociaż nie zawsze tak było.)
W wielu sytuacjach jest to coś, na co należy uważać przy defensywnym kodowaniu. Czasami trzeba np. Przejść przez plik tymczasowy, aby zobaczyć, czy polecenie, które wytworzyło to wyjście, zakończyło się powodzeniem, nawet jeśli idiom i wygoda w przeciwnym razie skierowałyby cię do korzystania z potoku powłoki.