Piszę skrypt powłoki i muszę sprawdzić, czy aplikacja terminalowa została zainstalowana. Chcę użyć do tego polecenia TRY / CATCH, chyba że istnieje lepszy sposób.
bash
shell
error-handling
Lee Probert
źródło
źródło
help test
może pomóc ci znaleźć rozwiązanie twojego problemu.trap
polecenia.Odpowiedzi:
Nie.
Bash nie ma tylu luksusów, jakie można znaleźć w wielu językach programowania.
Nie ma
try/catch
bash; jednak podobne zachowanie można osiągnąć za pomocą&&
lub||
.Używanie
||
:jeśli się
command1
nie powiedzie,command2
działa w następujący sposóbPodobnie użycie
&&
,command2
uruchomi się, jeślicommand1
się powiedzieNajbliższe przybliżenie
try/catch
jest następująceBash zawiera również pewne mechanizmy obsługi błędów
zatrzymuje skrypt, jeśli jedno proste polecenie zawiedzie.
A także dlaczego nie
if...else
. To twój najlepszy przyjaciel.źródło
#save your output
nie zawiódł, w przeciwnym razie blok „catch” będzie nadal wykonywany.if...else
konstruktu. Czy to oznacza, że polecenia bash są uznawane za „prawdomówne”, jeśli działają poprawnie, i „fałsz”, jeśli się nie udają?set -e
niekoniecznie jest to najlepszy sposób na robienie rzeczy; oto kilka kontrargumentów / przypadków specjalnych: mywiki.wooledge.org/BashFAQ/105W oparciu o niektóre odpowiedzi, które tutaj znalazłem, stworzyłem mały plik pomocnika do źródła dla moich projektów:
trycatch.sh
oto przykład, jak to wygląda w użyciu:
źródło
||
pocatch
i przed{}
blokiem? Myślałbym, że to&&
if False or run_if_failed()
oznacza, że zwarcie LUB wypróbowało pierwszą instrukcję, która nie zwróciła wartości true i przechodzi teraz do następnej instrukcji.&&
nie działałoby, ponieważ pierwsza instrukcja (try
) dała wartość false, co oznacza, żecatch
instrukcja nie jest konieczna zgodnie z regułą tautologiifalse&any equals false
. Tylko niedozwolone zwarcie AND / OR wykonałoby oba.Opracowałem prawie bezbłędną implementację try & catch w bash, która umożliwia pisanie kodu takiego jak:
Możesz nawet zagnieżdżać w sobie bloki try-catch!
Kod jest częścią mojej płyty bazowej / frameworku bash . To dodatkowo rozszerza pomysł try & catch na takie rzeczy jak obsługa błędów z funkcją śledzenia wstecznego i wyjątkami (plus kilka innych fajnych funkcji).
Oto kod odpowiedzialny tylko za try & catch:
Nie krępuj się używać, rozwidlać i dodawać - jest na GitHub .
źródło
my_output=$(try { code...; } catch { code...; })
Możesz użyć
trap
:try { block A } catch { block B } finally { block C }
przetłumaczyć na:
źródło
-E
Myślę, że też chcesz flagi, więc pułapka rozprzestrzenia się na funkcjeIstnieje wiele podobnych rozwiązań, które prawdopodobnie działają. Poniżej znajduje się prosty i działający sposób na wykonanie try / catch, wraz z wyjaśnieniem w komentarzach.
źródło
bash
nie przerywa wykonywania w przypadku, gdy coś wykryje stan błędu (chyba że ustawisz-e
flagę). Języki programowania, które oferują,try/catch
robią to w celu powstrzymania „ratowania” z powodu tej szczególnej sytuacji (stąd zwykle nazywane „wyjątkiem”).W
bash
zamiast tylko komenda w pytaniu wyjdzie z kodem wyjścia Większego niż 0, wskazując, że stan błędu. Można sprawdzić, że oczywiście, ale ponieważ nie ma automatycznego ratowanie czegokolwiek, o try / catch nie ma sensu. Po prostu brakuje tego kontekstu.Możesz jednak zasymulować ratowanie za pomocą podpowłok, które mogą zakończyć się w wybranym przez Ciebie punkcie:
Zamiast tego
some_condition
ze związkiemif
można również po prostu spróbować polecenie, a w przypadku, gdy nie powiedzie się (ma większą niż kodu exit 0), wyskoczyć:Niestety, stosując tę technikę, jesteś ograniczony do 255 różnych kodów wyjścia (1..255) i nie można używać żadnych przyzwoitych obiektów wyjątków.
Jeśli potrzebujesz więcej informacji, aby przekazać wraz z symulowanym wyjątkiem, możesz użyć standardowego poziomu podpowłoki, ale jest to nieco skomplikowane i może inne pytanie ;-)
Używając wyżej wspomnianej
-e
flagi do powłoki, możesz nawet usunąć tę jawnąexit
instrukcję:źródło
Jak wszyscy mówią, bash nie ma poprawnej składni try / catch obsługiwanej przez język. Możesz uruchomić bash z
-e
argumentem lub użyćset -e
w skrypcie, aby przerwać cały proces bash, jeśli dowolne polecenie ma niezerowy kod wyjścia. (Możesz takżeset +e
tymczasowo zezwolić na niepowodzenie poleceń).Tak więc jedną z technik symulacji bloku try / catch jest uruchomienie podprocesu w celu wykonania pracy z
-e
włączonym. Następnie w głównym procesie sprawdź kod powrotu podprocesu.Bash obsługuje ciągi heredoc, więc nie musisz pisać dwóch osobnych plików, aby to obsłużyć. W poniższym przykładzie TRY heredoc będzie działał w osobnej instancji bash, z
-e
włączoną opcją, więc podproces zawiesi się, jeśli jakiekolwiek polecenie zwróci niezerowy kod wyjścia. Następnie, wracając do głównego procesu, możemy sprawdzić kod powrotu, aby obsłużyć blok catch.Nie jest to odpowiedni blok try / catch obsługiwany przez język, ale może zadrapać cię podobnie.
źródło
Możesz to zrobić:
źródło
I masz pułapki http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html, który nie jest taki sam, ale inną technikę, której możesz użyć w tym celu
źródło
Używam bardzo prostej rzeczy:
źródło
||
jest()
włączona, działałby w podpowłoce i wychodził, nie powodując wyjścia głównej powłoki.{ }
Zamiast tego użyj grupowania.Poniżej znajduje się pełna kopia uproszczonego skryptu zastosowanego w mojej innej odpowiedzi . Oprócz dodatkowego sprawdzania błędów istnieje alias, który pozwala użytkownikowi zmienić nazwę istniejącego aliasu. Składnia jest podana poniżej. Jeśli
new_alias
parametr zostanie pominięty, alias zostanie usunięty.Pełny skrypt znajduje się poniżej.
źródło
Poniżej znajduje się przykład skryptu, który implementuje się
try/catch/finally
w bash.Przykładowe skrypty zacząć od tworzenia anonimowej FIFO, który jest używany do przekazywania wiadomości ciąg przez
command exception
lubthrow
do końca najbliższegotry
bloku. Tutaj wiadomości są usuwane z fifo i umieszczane w zmiennej tablicowej. Status jest zwracany przezreturn
iexit
poleceń i umieszczone w innej zmiennej. Aby wprowadzićcatch
blok, ten status nie może wynosić zero. Inne wymagania do wprowadzeniacatch
bloku są przekazywane jako parametry. Po osiągnięciu końcacatch
bloku status jest ustawiany na zero. Jeśli osiągnięty zostanie koniecfinally
bloku, a status nadal jest niezerowy, wykonywany jest dorozumiany rzut zawierający komunikaty i status. Skrypt wymaga wywołania funkcjitrycatchfinally
zawierającej nieobsługiwany moduł obsługi wyjątków.Składnia
trycatchfinally
polecenia jest podana poniżej.-c
Opcja dodaje stos wywołań do wiadomości wyjątków. Opcja umożliwia wyjście debugowania. Ta opcja włącza wyjątki poleceń. Ta opcja pozwala użytkownikowi zastąpić własny moduł obsługi wyjątków poleceń. Opcja dodaje stos wywołań do wyjścia debugowania. Opcja zastępuje domyślny plik wyjściowy, który jest . Ta opcja pozwala użytkownikowi zastąpić własną nieobsługiwaną procedurę obsługi wyjątków. Ta opcja pozwala użytkownikowi na przekazywanie wartości przez użycie polecenia Podstawienie. Jest to nazwa pliku fifo. Funkcja jest wywoływana przez jako podproces.-d
-e
-h
-k
-o
/dev/fd/2
-u
-v
fifo
function
trycatchfinally
Składnia
catch
polecenia jest podana poniżej.Opcje są zdefiniowane poniżej. Wartością pierwszej listy jest status. Kolejne wartości to komunikaty. Jeśli wiadomości jest więcej niż listy, pozostałe wiadomości są ignorowane.
-e
oznacza[[ $value == "$string" ]]
(wartość musi odpowiadać co najmniej jednemu ciągowi na liście)-n
oznacza[[ $value != "$string" ]]
(wartość nie może pasować do żadnego z ciągów na liście)-o
oznacza[[ $value != $pattern ]]
(wartość nie może pasować do żadnego z wzorców na liście)-p
oznacza[[ $value == $pattern ]]
(wartość ma dopasowanie co najmniej jednego wzorca na liście)-r
oznacza[[ $value =~ $regex ]]
(wartość musi pasować do co najmniej jednego rozszerzonego wyrażenia regularnego na liście)-t
oznacza[[ ! $value =~ $regex ]]
(wartość nie może pasować do żadnego z rozszerzonych wyrażeń regularnych na liście)try/catch/finally
Skrypt znajduje się poniżej. Aby uprościć skrypt dla tej odpowiedzi, większość kontroli błędów została usunięta. To zmniejszyło rozmiar o 64%. Kompletną kopię tego skryptu można znaleźć w mojej drugiej odpowiedzi .Poniżej znajduje się przykład, który zakłada, że powyższy skrypt jest przechowywany w pliku o nazwie
simple
.makefifo
Plik zawiera skrypt opisany w tej odpowiedzi . Przyjęto założenie, że plik o podanej nazwie4444kkkkk
nie istnieje, co powoduje wystąpienie wyjątku. Wyjście komunikatu błędu zls 4444kkkkk
polecenia jest automatycznie pomijane aż do odpowiedniegocatch
bloku.Powyższy skrypt został przetestowany przy użyciu
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17)
. Wynik działania tego skryptu pokazano poniżej.Kolejny przykład, w którym zastosowano a,
throw
można utworzyć, zastępując funkcjęMyFunction3
skryptem pokazanym poniżej.Składnia
throw
polecenia jest podana poniżej. Jeśli nie ma żadnych parametrów, zamiast tego używane są status i komunikaty zapisane w zmiennych.Wynik działania zmodyfikowanego skryptu pokazano poniżej.
źródło