set -e
kończy skrypt, jeśli napotkany zostanie niezerowy kod wyjścia, poza pewnymi warunkami. Podsumowując niebezpieczeństwa związane z jego użyciem w kilku słowach: nie zachowuje się tak, jak ludzie myślą.
Moim zdaniem należy go traktować jako niebezpieczny hack, który nadal istnieje wyłącznie w celach kompatybilności. set -e
Oświadczenie nie włącza powłokę z języka, który wykorzystuje kody błędów na język, który wykorzystuje przepływ sterowania wyjątku podobny, to jedynie słabo próbuje naśladować to zachowanie.
Greg Wooledge ma wiele do powiedzenia na temat zagrożeń związanych z set -e
:
W drugim linku znajdują się różne przykłady nieintuicyjnego i nieprzewidywalnego zachowania set -e
.
Niektóre przykłady nieintuicyjnego zachowania set -e
(niektóre z powyższego linku wiki):
ustaw -e
x = 0
niech x ++
echo „x to $ x”
Powyższe spowoduje przedwczesne zamknięcie skryptu powłoki, ponieważ let x++
zwraca 0, które jest traktowane przez let
słowo kluczowe jako wartość fałszowania i zamieniane w niezerowy kod wyjścia. set -e
zauważa to i cicho kończy skrypt.
ustaw -e
[-d / opt / foo] && echo „Ostrzeżenie: foo jest już zainstalowany. Zastąpi”. > I 2
echo „Instalowanie foo ...”
Powyższe działa zgodnie z oczekiwaniami, drukując ostrzeżenie, jeśli /opt/foo
już istnieje.
ustaw -e
check_previous_install () {
[-d / opt / foo] && echo „Ostrzeżenie: foo jest już zainstalowany. Zastąpi”. > I 2
}
check_previous_install
echo „Instalowanie foo ...”
Powyższe, pomimo że jedyną różnicą jest to, że pojedyncza linia została przekształcona w funkcję, zakończy się, jeśli /opt/foo
nie istnieje. Wynika to z faktu, że fakt, że działał pierwotnie, stanowi wyjątek od set -e
zachowania. Gdy a && b
zwraca wartość niezerową, jest ignorowana przez set -e
. Jednak teraz, gdy jest to funkcja, kod wyjścia funkcji jest równy kodowi wyjścia tej komendy, a funkcja zwracająca wartość niezerową po cichu zakończy skrypt.
ustaw -e
IFS = $ '\ n' read -d '' -r -a config_vars <config
Powyższe przeczyta tablicę config_vars
z pliku config
. Jak autor może chcieć, kończy się z błędem, jeśli go config
brakuje. Ponieważ autor może nie zamierzać, po cichu kończy, jeśli config
nie kończy się na nowej linii. Gdyby set -e
nie były tu użyte, wówczas config_vars
zawierałyby wszystkie wiersze pliku, niezależnie od tego, czy zakończyły się one nową linią.
Użytkownicy Sublime Text (i innych edytorów tekstu, które nieprawidłowo obsługują znaki nowej linii), wystrzegają się.
ustaw -e
should_audit_user () {
grupy grup lokalnych = „$ (grupy„ $ 1 ”)”
dla grupy w $ grupach; zrobić
if [„$ group” = audyt]; następnie zwróć 0; fi
gotowy
zwrot 1
}
if should_audit_user "$ user"; następnie
logger „Blah”
fi
Tutaj autor może zasadnie oczekiwać, że jeśli z jakiegoś powodu użytkownik $user
nie istnieje, groups
polecenie zakończy się niepowodzeniem, a skrypt zostanie zakończony, a użytkownik nie będzie mógł wykonać jakiegoś zadania bez kontroli. Jednak w tym przypadku set -e
wypowiedzenie nigdy nie obowiązuje. Jeśli $user
z jakiegoś powodu nie można go znaleźć, zamiast zakończyć skrypt, should_audit_user
funkcja zwróci niepoprawne dane, jakby set -e
nie działało.
Dotyczy to każdej funkcji wywoływanej z części warunku if
instrukcji, bez względu na to, jak głęboko jest zagnieżdżona, bez względu na to, gdzie jest zdefiniowana, bez względu na to, czy uruchomisz set -e
ją ponownie. Użycie if
w dowolnym momencie całkowicie wyłącza efekt do set -e
momentu pełnego wykonania bloku warunków. Jeśli autor nie jest świadomy tego pułapki lub nie zna całego stosu wywołań we wszystkich możliwych sytuacjach, w których można wywołać funkcję, wówczas napisze kod błędu i dostarczone fałszywe poczucie bezpieczeństwa set -e
będzie przynajmniej częściowo winić.
Nawet jeśli autor jest w pełni świadomy tego pułapki, obejście polega na napisaniu kodu w taki sam sposób, w jaki napisano by go bez set -e
, skutecznie czyniąc ten przełącznik mniej niż bezużytecznym; autor musi nie tylko napisać ręczny kod obsługi błędów, jakby set -e
nie obowiązywał, ale obecność set -e
może go oszukać, że nie muszą.
Niektóre dalsze wady set -e
:
- Zachęca niechlujny kod. Programy obsługi błędów są całkowicie zapomniane, mając nadzieję, że cokolwiek się nie powiedzie, zgłosi błąd w rozsądny sposób. Jednak w przypadku przykładów takich jak
let x++
powyżej nie ma to miejsca. Jeśli skrypt niespodziewanie umiera nieoczekiwanie, zwykle jest cichy, co utrudnia debugowanie. Jeśli skrypt nie umiera, a spodziewałeś się tego (patrz poprzedni punkt), masz na rękach bardziej subtelny i podstępny błąd.
- Prowadzi ludzi do fałszywego poczucia bezpieczeństwa. Zobacz ponownie punkt-
if
warunek-punkt.
- Miejsca, w których kończy się powłoka, nie są spójne między powłokami lub wersjami powłok. Możliwe jest przypadkowe napisanie skryptu, który zachowuje się inaczej w starszej wersji basha, ponieważ zachowano go w
set -e
różnych wersjach.
set -e
jest kwestią sporną, a niektórzy zdają sobie sprawę z otaczających go problemów, którzy go zalecają, podczas gdy inni zalecają ostrożność, gdy jest aktywny, aby poznać pułapki. Jest wielu początkujących skryptów powłoki, którzy polecają set -e
wszystkie skrypty jako uniwersalne rozwiązanie w przypadku błędów, ale w rzeczywistości tak nie działa.
set -e
nie zastąpi edukacji.