2014-06-27 13 views
6

W skrypcie powłoki, który ma zostać wykonany, mogę przerwać wykonywanie błędów za pomocą set -e.Bash: zatrzymaj się przy błędzie w skrypcie źródłowym

Jednak w skrypcie źródłowym użycie set -e zabije oryginalną powłokę, jeśli późniejsza komenda zakończy działanie ze statusem błędu.

source set_e.sh 
./exit_1.sh 
# shell dies 

Trywialny rozwiązaniem byłoby set +e na końcu skryptu, ale to byłoby złamać rodziców set -e jeśli używany (która może bardzo dobrze się stało, gdyby ktoś owija mój skrypt w przyszłości).

Jak mogę uzyskać funkcjonalność "prześlij-pomyłki" w skryptach źródłowych?

+0

@BlueMoon PO post wyjaśnia, dlaczego to nie zadziała. –

+0

Nie można ustawić pułapki wyjścia w środowisku wywołującym i obsługiwać go tam? –

Odpowiedz

0

Możesz wykryć przez set -o, jeśli opcja errexit została ustawiona na początku skryptu źródłowego i odzyskać oryginalną wartość na końcu skryptu źródłowego.

2

Można sprawdzić, czy set -e jest już włączony, a następnie ustawić go warunkowo:

[[ $- == *e* ]] && state=-e || state=+e 
set -e 
yourcode 
set "$state" 

jednak pamiętać, że set -e jest wadliwy i skrypty nie powinny zależeć od niego pod względem poprawności. Na przykład, jeśli ktoś źródła skryptu w instrukcji if, set -e mogą nie działać poprawnie:

echo ' 
set -e 
ls file.that.doesnt.exist 
echo "Success" 
' > yourscript 

set -e 
if ! source yourscript 
then 
    echo "Initialization failed" 
fi 
echo "Done" 

następnie set -e będzie już przerwać w przypadku niepowodzenia w yourscript w bash 4.3.30:

ls: cannot access file.that.doesnt.exist: No such file or directory 
Success 
Done 

while będzie on opuścić cały skrypt w bash 2, 3 i aż do 4.2:

ls: cannot access file.that.doesnt.exist: No such file or directory 
+1

Druga część wprowadza w błąd - jeśli 'yourscript' ustawia' errexit', to kod wrappera przerwie na nim błędy (testowane z bash 4.2.x). Może się to wydawać sprzeczne z intuicją w porównaniu do zwykłego użycia powłoki if-then-else, ale jeśli pozyskujesz nierzetelny kod, oczekiwanie, że zapakujesz je w podpowłokę, nie wydaje się wcale nieuzasadnione. –

+1

@JosipRodin Widzę, że bash 2 i 3 przerwał cały skrypt, ale na 4.3.30 (1) -release go nie przerwać zgodnie z opisem. Ciekawe wiedzieć, że zachowanie tak bardzo się zmieniło. –

+0

Dobry połów. Myślę, że obecne zachowanie jest zgodne z główną radą - używanie podpowłoki. Na przykład, jeśli wykonasz: 'set + e; (. yourscript); jeśli [$? -ne 0]; następnie echo "Inicjalizacja nie powiodła się"; fi' - wynik jest dość logiczny. –

3

zmian set -e do return 0 (lub wybierz swoją ulubioną liczbę całkowitą zamiast 0). Możesz myśleć o tym, traktując plik źródłowy jako funkcję. Na przykład:

$ cat myreturn.sh 
#!/bin/bash 

let i=0 

while test "$i" -lt 10; do 

    echo "i $i" 
    if test "$i" -gt 5 ; then 
     return 5 
    fi 
    sleep 1 
    ((i+=1)) 

done 

return 4 

$ (. myreturn.sh) 
i 0 
i 1 
i 2 
i 3 
i 4 
i 5 
i 6 

$ echo $? 
5 
+0

Dlaczego ta odpowiedź nie jest pierwsza? Wielkie dzięki!! – eplaut

4

To niemożliwe. Można jednak zdecydować się na stosowanie podpowłoce jeśli chcesz:

(
    set -e 
    source another.sh 
) 

Tylko że środowisko działania skryptu nigdy nie może być zmieniona przez wywoływanego skryptu.

Uwaga: Może być ważne, aby oddzielić oba polecenia za pomocą znaku nowej linii i nie używać średnika.

2

Cóż, pytanie nie jest bardzo jasne Re: co jego autor chciał po przechwytywanie błędów w pochodzących skryptu, jednak jako punkt wejścia do roztworu dodaje się będzie wystarczyć:

można ustawić pułapki na ERR i obsługiwać błąd wewnątrz skryptu źródłowego tam. Poniżej znajdują się dwa scenariusze: jeden ze skryptem źródłowym za pomocą "set -e", a drugi ze skryptem źródłowym NIE używającym "set -e".

Podstawowym skrypt jest wywołaniem wtórnego skrypt z określonymi „set -e” i łapie błąd:

[galaxy => ~]$ cat primary.sh 
#!/bin/sh 

set -e 
echo 'Primary script' 
trap 'echo "Got an error from the secondary script"' ERR 
source secondary.sh 
trap - ERR 
echo 'Primary script exiting' 
[galaxy => ~]$ cat secondary.sh 
#!/bin/sh 

echo 'Secondary script' 
set -e 
echo 'Secondary script generating an error' 
false 
echo 'Secondary script - should not be reached' 
[galaxy => ~]$ ./primary.sh 
Primary script 
Secondary script 
Secondary script generating an error 
Got an error from the secondary script 
[galaxy => ~]$ 

Podstawowym skrypt jest wywołanie skryptu wtórny bez „set -e” i połowów błąd:

[galaxy => ~]$ cat primary.sh 
#!/bin/sh 

set -e 
echo 'Primary script' 
trap 'echo "Got an error from the secondary script"' ERR 
source secondary.sh 
trap - ERR 
echo 'Primary script exiting' 
[galaxy => ~]$ cat secondary.sh 
#!/bin/sh 

echo 'Secondary script' 
echo 'Secondary script generating an error' 
false 
echo 'Secondary script - should not be reached if sourced by primary.sh' 
[galaxy => ~]$ ./primary.sh 
Primary script 
Secondary script 
Secondary script generating an error 
Got an error from the secondary script 
[galaxy => ~]$ 

Jako bonus: przechwytywanie błąd w skrypcie i pochodzących kontynuując:

[galaxy => ~]$ cat primary.sh 
#!/bin/sh 

echo 'Primary script' 
i=0 
while [ $i = 0 ]; do 
    i=1 
    trap 'echo "Got an error from the secondary script"; break' ERR 
    source secondary.sh 
done 
trap - ERR 
echo 'Primary script exiting' 
[galaxy => ~]$ cat secondary.sh 
#!/bin/sh 

echo 'Secondary script' 
echo 'Secondary script generating an error' 
false 
echo 'Secondary script - should not be reached if sourced by primary.sh' 
[galaxy => ~]$ ./primary.sh 
Primary script 
Secondary script 
Secondary script generating an error 
Got an error from the secondary script 
Primary script exiting 
[galaxy => ~]$ 
Powiązane problemy