2013-02-20 12 views
11

Jestem trochę zdezorientowany. Moim celem jest, aby skrypt bash zakończył się niezerowym kodem wyjścia, gdy któreś z poleceń w skrypcie nie powiedzie się. Używając flagi -e, założyłem, że tak będzie, nawet przy użyciu podpowłok. Poniżej znajduje się uproszczony przykład:Dlaczego bash nie jest zakończona flagą -e, gdy zawiedzie podpowłoki?

#!/bin/bash -e 

(false) 

echo $? 
echo "Line reached!" 

Tutaj jest wyjście, gdy prowadził:

[$]>Tests/Exec/continuous-integration.sh 
1 
Line reached! 

Bash wersja: 3.2.25 CentOS

+0

Czy jest jakaś szansa na wszystko możesz zaktualizować swoją wersję bash, ponieważ ten dokładny skrypt działa zgodnie z przeznaczeniem w 4.1.5. Być może to twoja "fałszywa" wersja –

Odpowiedz

8

Wydaje się, że jest to związane z twoją wersją bash. Na maszynach, do których mam dostęp, bash w wersjach 3.1.17 i 3.2.3 wykazuje to zachowanie, bash 4.1.5 tego nie robi.

Choć nieco brzydki, to rozwiązanie, które działa w obu wersjach może być coś takiego:

#!/bin/bash -e 

(false) || exit $? 

echo $? 
echo "Line reached!" 

Istnieje kilka notatek w źródle changelogu bash który dotyczył błędów z opcją set -e.

+0

Ah, dzięki za kopanie, to było to! Dzięki za sugerowaną odpowiedź, właśnie to zrobię. –

+1

Nie wiem, który system operacyjny jest włączony, ale np. Niestety, Mountain Lion nadal zawiera bash 3. –

0

Widziałem to zachowanie w bash w wersji 3.2.51 zarówno na SuSE 11.3 i Mac OS przed El Capitan. Bash 3.2.57 na El Capitan ma "poprawne" zachowanie, np. Bash 4.

Jednak, obejście proponowane powyżej, dodanie "|| exit $?" po zamykającym okienku podpowaty, pokonuje intencję flagi -e bez względu na wersję basha. Z man bash:

-e Zakończ natychmiast jeśli polecenie proste (zobacz GRAMATYKA POWŁOKI powyżej) wyjście z niezerowym. Powłoka nie zostanie zakończona, jeśli polecenie, które się nie powiedzie, jest częścią listy poleceń bezpośrednio po chwili lub dopóki słowo kluczowe, część testu w instrukcji if, nie będzie częścią & & lub || lista, ...

Podpatka, a następnie "|| exit $?" najwyraźniej liczy się jako lista poleceń; a flaga bash -e nie będzie stosować się do polecenia ANY wewnątrz podpowłoki. Spróbuj go:

$ set -e 
$ (echo before the error; false; echo after the error, status $?;) || echo after the subshell, status $? 
before the error 
after the error, status 1 
$ 

Ponieważ podpowłoki następuje ||, że „echo po błędzie” jest prowadzony, nawet przy ustawionej -e. Co więcej, podpowłodzenie kończy 0, ponieważ to "echo" działało. Więc "|| exit $?" nawet nie uruchomi "wyjścia". Prawdopodobnie nie tego chcieliśmy!

O ile mi wiadomo, następująca formuła jest zgodna z wersjami bash, niezależnie od tego, czy honorują bash -e po subshell, czy nie. To nawet zachowuje się poprawnie, jeśli -e flag dzieje się zresetować:

Dodaj następujący wiersz bezpośrednio po nawiasie zamykającym każdej podpowłoce w skrypcie bash:

case $?/$- in (0/*) ;; (*/*e*) exit $? ;; esaC# honor bash -e flag when subshell returns 
Powiązane problemy