Chcę zgłosić błąd w skrypcie Bash z komunikatem „Przypadki testowe nie powiodły się !!!”. Jak to zrobić w Bash?
Na przykład:
if [ condition ]; then
raise error "Test cases failed !!!"
fi
linux
bash
shell
error-handling
Naveen Kumar
źródło
źródło
echo you screwed up at ... | mail -s BUG $bugtrackeremailaddress
?Odpowiedzi:
Zależy to od tego, gdzie chcesz przechowywać komunikat o błędzie.
Możesz wykonać następujące czynności:
Lub następujące:
Zgłaszając wyjątek, zatrzymujesz wykonywanie programu.
Możesz również użyć czegoś takiego, jak
exit xxx
gdziexxx
jest kod błędu, który możesz chcieć przywrócić do systemu operacyjnego (od 0 do 255). Tu125
i64
są tylko losowe kody można wyjść z. Kiedy trzeba, aby wskazać, że program OS zatrzymany nienormalnie (wystąpił np. Błąd), trzeba zdać niezerowy kod wyjścia doexit
.Jak zauważył @chepner , możesz to zrobić
exit 1
, co będzie oznaczać nieokreślony błąd .źródło
1>&2
radeexit
sama używa statusu wyjścia ostatnio wykonanego polecenia, który może wynosić 0.exit 1
, co zgodnie z konwencją oznacza nieokreślony błąd.Podstawowa obsługa błędów
Jeśli moduł uruchamiający przypadek testowy zwraca niezerowy kod dla testów zakończonych niepowodzeniem, możesz po prostu napisać:
Albo jeszcze krócej:
Lub najkrótszy:
Aby wyjść z kodem wyjścia test_handler:
Zaawansowana obsługa błędów
Jeśli chcesz przyjąć bardziej kompleksowe podejście, możesz skorzystać z modułu obsługi błędów:
następnie wywołaj go po uruchomieniu przypadku testowego:
lub
Zalety posiadania takiej obsługi błędów
exit_if_error
to:if
bloków, które testują kody wyjścia pod kątem błędówObsługa błędów i biblioteka logowania
Oto pełna implementacja obsługi błędów i rejestrowania:
https://github.com/codeforester/base/blob/master/lib/stdlib.sh
Powiązane posty
__FILE__
,__LINE__
w bashźródło
Istnieje kilka innych sposobów rozwiązania tego problemu. Zakładając, że jednym z twoich wymagań jest uruchomienie skryptu / funkcji powłoki zawierającej kilka poleceń powłoki i sprawdzenie, czy skrypt został uruchomiony pomyślnie, i wyświetlenie błędów w przypadku awarii.
Polecenia powłoki generalnie opierają się na zwracanych kodach wyjścia, aby powiadomić powłokę o powodzeniu lub niepowodzeniu z powodu nieoczekiwanych zdarzeń.
Więc to, co chcesz zrobić, należy do tych dwóch kategorii
W zależności od tego, który chcesz zrobić, dostępne są opcje powłoki. W pierwszym przypadku, powłoka zapewnia odpowiednią opcję z
set -e
i na sekundę można zrobićtrap
naEXIT
Czy powinienem używać
exit
w moim skrypcie / funkcji?Używanie
exit
ogólnie poprawia czytelność W niektórych procedurach, gdy znasz odpowiedź, chcesz natychmiast wyjść z procedury wywoływania. Jeśli procedura jest zdefiniowana w taki sposób, że po wykryciu błędu nie wymaga dalszego czyszczenia, brak natychmiastowego zakończenia oznacza, że musisz napisać więcej kodu.Dlatego w przypadkach, gdy musisz wykonać czynności porządkowe w skrypcie, aby zakończyć działanie skryptu, lepiej nie używać
exit
.Czy powinienem użyć
set -e
do błędu przy wyjściu?set -e
była próbą dodania "automatycznego wykrywania błędów" do powłoki. Jego celem było spowodowanie przerwania działania powłoki za każdym razem, gdy wystąpi błąd, ale wiąże się z wieloma potencjalnymi pułapkami, na przykładPolecenia wchodzące w skład testu if są odporne. W tym przykładzie, jeśli spodziewasz się, że przerwie on
test
sprawdzenie nieistniejącego katalogu, nie zrobi tego, przechodzi do warunku elsePolecenia w potoku innym niż poprzedni są odporne. W poniższym przykładzie, ponieważ uwzględniono kod zakończenia ostatnio wykonanego (najbardziej po prawej) polecenia (
cat
) i zakończył się on pomyślnie. Można tego uniknąć, ustawiającset -o pipefail
opcję, ale nadal jest to zastrzeżenie.Zalecane do użycia -
trap
przy wyjściuWerdykt jest taki, że jeśli chcesz być w stanie obsłużyć błąd zamiast ślepego zamykania, zamiast używać
set -e
, użyj atrap
naERR
pseudo sygnale.ERR
Pułapka nie jest do uruchomienia kodu, gdy sama powłoka kończy pracę z niezerowym kodem błędu, ale kiedy każdy run komenda tą skorupą, która nie jest częścią stanu (jak na raziecmd
, czycmd ||
) wychodzi ze stanem wyjściowym niezerowej .Ogólna praktyka jest taka, że definiujemy procedurę obsługi pułapki, aby zapewnić dodatkowe informacje debugowania, która linia i co powoduje zakończenie. Pamiętaj, że kod zakończenia ostatniego polecenia, które spowodowało
ERR
sygnał, byłby nadal dostępny w tym momencie.i po prostu używamy tego programu obsługi, jak poniżej, na górze skryptu, który nie działa
Łącząc to razem w prostym skrypcie, który zawierał
false
w linii 15, informacje, które otrzymasz jakotrap
Zapewnia również opcje niezależnie od błędu po prostu uruchomić oczyszczanie po zakończeniu powłoki (np twoje wyjść skrypt powłoki), na sygnaleEXIT
. Możesz także przechwytywać wiele sygnałów w tym samym czasie. Listę obsługiwanych sygnałów do pułapkowania można znaleźć na stronie trap.1p - podręcznika LinuxInną rzeczą, na którą należy zwrócić uwagę, jest zrozumienie, że żadna z podanych metod nie działa, jeśli masz do czynienia z powłokami podrzędnymi, w którym to przypadku może być konieczne dodanie własnej obsługi błędów.
Na podpowłoce z
set -e
nie zadziała.false
Ogranicza się do sub-shell i nigdy nie pobiera propagowane do powłoki macierzystej. Aby wykonać tutaj obsługę błędów, dodaj własną logikę do wykonania(false) || false
To samo dzieje się
trap
również z . Poniższa logika nie zadziała z powodów wymienionych powyżej.źródło
Oto prosta pułapka, która wypisuje do STDERR ostatni argument dowolnego argumentu, który się nie powiódł, zgłasza wiersz, w którym wystąpił błąd, i zamyka skrypt z numerem linii jako kodem zakończenia. Pamiętaj, że nie zawsze są to świetne pomysły, ale pokazuje to kreatywne aplikacje, na których możesz zbudować.
Umieściłem to w skrypcie z pętlą, aby to przetestować. Po prostu sprawdzam trafienie w jakieś losowe liczby; możesz użyć rzeczywistych testów. Jeśli muszę się wycofać, nazywam fałsz (co uruchamia pułapkę) z wiadomością, którą chcę rzucić.
Aby uzyskać bardziej rozbudowaną funkcjonalność, niech pułapka wywoła funkcję przetwarzania. Zawsze możesz użyć instrukcji case na swoim arg ($ _), jeśli chcesz zrobić więcej porządków itp. Przypisz do zmiennej, aby uzyskać trochę cukru syntaktycznego -
Przykładowe dane wyjściowe:
Oczywiście, że możesz
Dużo miejsca na ulepszenia projektu.
Wady obejmują fakt, że
false
nie jest ładna (a więc cukier), a inne rzeczy, w których wyzwolenie pułapki może wyglądać trochę głupio. Mimo to podoba mi się ta metoda.źródło
Masz 2 opcje: Przekieruj dane wyjściowe skryptu do pliku, Wprowadź plik dziennika do skryptu i
Tutaj zakładasz, że skrypt wyświetla wszystkie niezbędne informacje, w tym ostrzeżenia i komunikaty o błędach. Następnie możesz przekierować dane wyjściowe do wybranego pliku.
Powyższe polecenie przekierowuje zarówno standardowe wyjście, jak i wyjście błędu do pliku dziennika.
Korzystając z tego podejścia, nie musisz wprowadzać pliku dziennika do skryptu, więc logika jest nieco łatwiejsza.
W swoim skrypcie dodaj plik dziennika albo przez zakodowanie go na stałe:
lub przekazując go przez parametr:
Dobrym pomysłem jest dodanie sygnatury czasowej w momencie wykonywania do pliku dziennika w górnej części skryptu:
Następnie możesz przekierować komunikaty o błędach do pliku dziennika
Spowoduje to dołączenie błędu do pliku dziennika i kontynuowanie wykonywania. Jeśli chcesz zatrzymać wykonywanie, gdy wystąpią krytyczne błędy, możesz użyć
exit
skryptu:Należy zauważyć, że
exit 1
oznacza to, że program przestał działać z powodu nieokreślonego błędu. Możesz to dostosować, jeśli chcesz.Korzystając z tego podejścia, możesz dostosować swoje dzienniki i mieć inny plik dziennika dla każdego składnika skryptu.
Jeśli masz stosunkowo mały skrypt lub chcesz wykonać skrypt innej osoby bez modyfikowania go, pierwsze podejście jest bardziej odpowiednie.
Jeśli zawsze chcesz, aby plik dziennika znajdował się w tej samej lokalizacji, jest to lepsza opcja niż 2. Również jeśli utworzyłeś duży skrypt z wieloma komponentami, możesz chcieć rejestrować każdą część inaczej, a drugie podejście jest jedyne opcja.
źródło
Często uważam, że przydatne jest napisanie funkcji do obsługi komunikatów o błędach, aby kod był ogólnie bardziej przejrzysty.
Pobiera kod błędu z poprzedniego polecenia i używa go jako domyślnego kodu błędu podczas zamykania całego skryptu. Odnotowuje również czas, z mikrosekundami, w których jest obsługiwany (data GNU
%N
to nanosekundy, które później skracamy do mikrosekund).Jeśli pierwsza opcja to zero lub dodatnia liczba całkowita, staje się kodem zakończenia i usuwamy go z listy opcji. Następnie zgłaszamy wiadomość do błędu standardowego, z nazwą skryptu, słowem „ERROR” i czasem (używamy rozwijania parametrów, aby skrócić nanosekundy do mikrosekund, lub w przypadku czasów innych niż GNU, aby skrócić np.
12:34:56.%N
Do12:34:56
). Dwukropek i spacja są dodawane po słowie ERROR, ale tylko wtedy, gdy pojawia się komunikat o błędzie. Na koniec wychodzimy ze skryptu za pomocą wcześniej określonego kodu wyjścia, wyzwalając wszelkie pułapki w normalny sposób.Kilka przykładów (załóżmy, że kod istnieje
script.sh
):źródło