set -ekoń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 -eOś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 letsłowo kluczowe jako wartość fałszowania i zamieniane w niezerowy kod wyjścia. set -ezauważ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/foojuż 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/foonie istnieje. Wynika to z faktu, że fakt, że działał pierwotnie, stanowi wyjątek od set -ezachowania. Gdy a && bzwraca 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_varsz pliku config. Jak autor może chcieć, kończy się z błędem, jeśli go configbrakuje. Ponieważ autor może nie zamierzać, po cichu kończy, jeśli confignie kończy się na nowej linii. Gdyby set -enie były tu użyte, wówczas config_varszawierał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 $usernie istnieje, groupspolecenie 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 -ewypowiedzenie nigdy nie obowiązuje. Jeśli $userz jakiegoś powodu nie można go znaleźć, zamiast zakończyć skrypt, should_audit_userfunkcja zwróci niepoprawne dane, jakby set -enie działało.
Dotyczy to każdej funkcji wywoływanej z części warunku ifinstrukcji, 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 -eją ponownie. Użycie ifw dowolnym momencie całkowicie wyłącza efekt do set -emomentu 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 -ebę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 -enie obowiązywał, ale obecność set -emoż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-
ifwarunek-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 -eróżnych wersjach.
set -ejest 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 -ewszystkie skrypty jako uniwersalne rozwiązanie w przypadku błędów, ale w rzeczywistości tak nie działa.
set -e nie zastąpi edukacji.