Piszę skrypt w Bash, aby przetestować kod. Jednak głupio wydaje się uruchamianie testów, jeśli kompilacja kodu nie powiedzie się, w takim przypadku po prostu przerywam testy.
Czy jest jakiś sposób, aby to zrobić bez owijania całego skryptu w pętli while i używania przerw? Coś jak dun dun goto?
1
konsekwentnie. Jeśli skrypt ma być uruchamiany przez inny skrypt, możesz zdefiniować własny zestaw kodów statusu o szczególnym znaczeniu. Na przykład1
== testy nie powiodły się,2
== kompilacja nie powiodła się. Jeśli skrypt jest częścią czegoś innego, konieczne może być dostosowanie kodów w celu dostosowania do stosowanych tam praktyk. Na przykład, gdy część zestawu testów jest uruchamiana przez automake, kod77
służy do oznaczenia pominięcia testu.exit #
polecenie w funkcji, a nie w skrypcie. (W takim przypadku użyjreturn #
zamiast tego.)exit 0
wyjdź ze skryptu i zwróci 0 (informując inne skrypty, które mogłyby wykorzystać wynik tego skryptu, to się udało)Użyj zestawu -e
Skrypt zakończy się po pierwszej linii, która się nie powiedzie (zwraca niezerowy kod wyjścia). W takim przypadku polecenie, które zawiedzie 2 , nie zostanie uruchomione.
Jeśli chcesz sprawdzić status zwrotu każdej komendy, skrypt wyglądałby następująco:
Z ustawieniem -e wyglądałoby to tak:
Każde polecenie, które się nie powiedzie, spowoduje awarię całego skryptu i zwróci status wyjścia, który można sprawdzić za pomocą $? . Jeśli twój skrypt jest bardzo długi lub tworzysz wiele rzeczy, stanie się dość brzydki, jeśli dodasz wszędzie sprawdzanie statusu zwrotu.
źródło
set -e
wciąż może zrobić jakieś polecenia zjazdu z błędami bez zatrzymywania skrypt:command 2>&1 || echo $?
.set -e
przerwie skrypt, jeśli potok lub struktura poleceń zwróci wartość niezerową. Na przykładfoo || bar
zakończy się niepowodzeniem tylko wtedy, gdy obafoo
ibar
zwrócą wartość niezerową. Zwykle dobrze napisany skrypt bash będzie działał, jeśli dodaszset -e
na początku, a dodatek działa jak automatyczna kontrola poprawności: przerwij skrypt, jeśli coś pójdzie nie tak.set -o pipefail
opcję.set -e
byłby sprawiedliwymake || exit $?
.set -u
. Spójrz na nieoficjalnej bash trybie ścisłym :set -euo pipefail
.Pewien facet z SysOps nauczył mnie techniki trójpalczastego pazura:
Te funkcje to * NIX OS i odporny na smak powłoki. Umieść je na początku skryptu (bash lub w inny sposób),
try()
dołącz swoje oświadczenie i kod.Wyjaśnienie
(na podstawie komentarza latających owiec ).
yell
: wypisz nazwę skryptu i wszystkie argumenty dostderr
:$0
jest ścieżką do skryptu;$*
wszystkie są argumentami.>&2
oznacza>
przekierowanie standardowego wejścia do & pipe2
. fajka1
byłabystdout
sama.die
robi to samo coyell
, ale wychodzi ze statusem wyjścia innym niż 0 , co oznacza „niepowodzenie”.try
używa||
(booleanOR
), który ocenia prawą stronę tylko w przypadku niepowodzenia lewej.$@
to znowu wszystkie argumenty, ale inne .źródło
$0
jest ścieżką do skryptu.$*
wszystkie są argumentami.>&2
oznacza „>
przekieruj standardowe wyjście na&
potok2
”. rura 1 byłaby sama stdout. więc krzyczy przedrostek wszystkich argumentów nazwą skryptu i wypisuje na stderr. die robi to samo co krzyk , ale wychodzi ze statusem wyjścia innym niż 0, co oznacza „niepowodzenie”. try używa wartości logicznej lub||
, która ocenia prawą stronę tylko wtedy, gdy lewa nie zawiodła.$@
to znowu wszystkie argumenty, ale inne . mam nadzieję, że to wszystko wyjaśniadie() { yell "$1"; exit $2; }
można było przekazać wiadomość i kod zakończenia za pomocądie "divide by zero" 115
.yell
idie
. Jednaktry
nie tak bardzo. Czy możesz podać przykład swojego użycia?Jeśli wywołasz skrypt za pomocą
source
, możesz użyćreturn <x>
gdzie<x>
będzie status wyjścia skryptu (użyj wartości niezerowej dla błędu lub fałszu). Ale jeśli wywołasz skrypt wykonywalny (tj. Bezpośrednio z jego nazwą pliku), instrukcja return spowoduje skargę (komunikat o błędzie „return: może tylko„ wrócić ”z funkcji lub skryptu źródłowego).Jeśli
exit <x>
zostanie użyte zamiast tego, po wywołaniu skryptusource
nastąpi wyjście z powłoki, która go uruchomiła, ale skrypt wykonywalny po prostu zakończy się, zgodnie z oczekiwaniami.Aby obsłużyć obie sprawy w tym samym skrypcie, możesz użyć
To obsłuży dowolne wywołanie. Zakłada się, że użyjesz tej instrukcji na najwyższym poziomie skryptu. Odradzałbym bezpośrednie wychodzenie ze skryptu z funkcji.
Uwaga:
<x>
ma być tylko liczbą.źródło
Często dołączam funkcję o nazwie run () do obsługi błędów. Każde wywołanie, które chcę wykonać, jest przekazywane do tej funkcji, więc cały skrypt kończy działanie po awarii. Zaletą tego rozwiązania nad zestawem -e jest to, że skrypt nie wychodzi cicho po awarii linii i może powiedzieć ci, na czym polega problem. W poniższym przykładzie trzecia linia nie jest wykonywana, ponieważ skrypt kończy się po wywołaniu wartości false.
źródło
set -e option
. Następnie polecenie, ponieważ jest z argumentami, użyłem apostrofów aby uniknąć problemów bash tak:runTry 'mysqldump $DB_PASS --user="$DB_USER" --host="$BV_DB_HOST" --triggers --routines --events --single-transaction --verbose $DB_SCHEMA $tables -r $BACKUP_DIR/$tables$BACKUP_FILE_NAME'
. Uwaga Zmieniłem nazwę funkcji na runTry.eval
jest potencjalnie niebezpieczne, jeśli zaakceptujesz dowolne dane wejściowe, ale poza tym wygląda to całkiem ładnie.Zamiast
if
konstruować, możesz wykorzystać ocenę zwarcia :Zwróć uwagę na parę nawiasów, która jest konieczna ze względu na priorytet operatora przemienności.
$?
to specjalna zmienna ustawiona na kod zakończenia ostatnio wywoływanej komendy.źródło
command -that --fails || exit $?
, działa bez nawiasów, coecho $[4/0]
takiego powoduje, że ich potrzebujemy?echo $[4/0] || exit $?
) bash nigdy nie wykonaecho
, nie mówiąc już o przestrzeganiu||
.Mam to samo pytanie, ale nie mogę go zadać, ponieważ byłoby duplikatem.
Akceptowana odpowiedź przy użyciu polecenia exit nie działa, gdy skrypt jest nieco bardziej skomplikowany. Jeśli użyjesz procesu działającego w tle, aby sprawdzić warunek, wyjście kończy tylko ten proces, ponieważ działa w podpowłoce. Aby zabić skrypt, musisz go jawnie zabić (przynajmniej to jedyny sposób, jaki znam).
Oto mały skrypt, jak to zrobić:
To lepsza odpowiedź, ale wciąż niekompletna. Naprawdę nie wiem, jak pozbyć się części boomu .
źródło