Przerywanie skryptu powłoki, jeśli jakieś polecenie zwraca niezerową wartość?

Mam skrypt powłoki Bash, który wywołuje wiele poleceń. Chciałbym, aby skrypt powłoki automatycznie zakończył działanie z wartością zwracaną 1, jeśli któreś z poleceń zwróci wartość niezerową.

Czy jest to możliwe bez jawnego sprawdzania wyniku każdego polecenia?

Np.

dosomething1
if [[ $? -ne 0 ]]; then
    exit 1
fi

dosomething2
if [[ $? -ne 0 ]]; then
    exit 1
fi
Author: Mat, 2009-05-04

9 answers

Dodaj to do początku skryptu:

set -e

Spowoduje to natychmiastowe wyjście powłoki, jeśli proste polecenie zakończy działanie z niezerową wartością końcową. Proste polecenie to dowolne polecenie nie będące częścią if, while, lub until test, lub częścią listy & & lub||.

Zobacz stronę podręcznika bash(1) na wewnętrznej komendzie "set", aby uzyskać więcej szczegółów.

Osobiście uruchamiam prawie wszystkie skrypty powłoki z "set-e". To naprawdę irytujące mieć skrypt uparcie kontynuować, gdy coś w środku zawodzi i łamie założenia do reszty scenariusza.

 610
Author: Ville Laurikari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-21 11:18:12

Aby dodać do zaakceptowanej odpowiedzi:

Pamiętaj, że set -e czasami to za mało, szczególnie jeśli masz rury.

Na przykład, załóżmy, że masz ten skrypt

#!/bin/bash
set -e 
./configure  > configure.log
make

... co działa zgodnie z oczekiwaniami: błąd w configure przerywa wykonanie.

Jutro dokonasz pozornie błahej zmiany:

#!/bin/bash
set -e 
./configure  | tee configure.log
make

... a teraz to nie działa. Jest to wyjaśnione tutaj , a obejście (tylko Bash) jest dostępne:

#!/bin/bash
set -e 
set -o pipefail

./configure  | tee configure.log
make
 163
Author: leonbloy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-22 18:57:06

Instrukcje if w twoim przykładzie są niepotrzebne. Po prostu zrób to tak:

dosomething1 || exit 1

Jeśli skorzystasz z porad Ville Laurikari i użyjesz set -e to dla niektórych poleceń może być konieczne użycie tego:

dosomething || true

|| true spowoduje, że potok poleceń będzie miał zwracaną wartość true, nawet jeśli polecenie się nie powiedzie, więc opcja -e nie zabije skryptu.

 70
Author: Zan Lynx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-04 19:03:39

Jeśli masz czyszczenie, które musisz wykonać przy wyjściu, możesz również użyć 'trap' z pseudo-sygnałem ERR. Działa to tak samo jak zalewkowanie INT lub dowolnego innego sygnału; bash rzuca błąd, jeśli jakiekolwiek polecenie zakończy działanie z wartością niezerową:

# Create the trap with   
#    trap COMMAND SIGNAME [SIGNAME2 SIGNAME3...]
trap "rm -f /tmp/$MYTMPFILE; exit 1" ERR INT TERM
command1
command2
command3
# Partially turn off the trap.
trap - ERR
# Now a control-C will still cause cleanup, but
# a nonzero exit code won't:
ps aux | grep blahblahblah

Lub, szczególnie jeśli używasz "set-e", możesz zamknąć pułapkę; pułapka zostanie wykonana, gdy skrypt zakończy się z jakiegokolwiek powodu, włączając normalny koniec, przerwania, wyjście spowodowane opcją-e, itp.

 26
Author: fholo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-07 20:58:11

Uruchom go z -e LUB set -e na górze.

Zobacz też set -u.

 13
Author: lumpynose,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-04 13:48:37

Zmienna $? jest rzadko potrzebna. Pseudo-idiom command; if [ $? -eq 0 ]; then X; fi powinien być zawsze zapisywany jako if command; then X; fi.

Przypadki, w których $? jest wymagane, są wtedy, gdy trzeba je sprawdzić pod wieloma wartościami:

command
case $? in
  (0) X;;
  (1) Y;;
  (2) Z;;
esac

Lub gdy$? wymaga ponownego użycia lub innego manipulowania:

if command; then
  echo "command successful" >&2
else
  ret=$?
  echo "command failed with exit code $ret" >&2
  exit $ret
fi
 10
Author: Mark Edgar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-16 10:18:54

Wyrażenie podobne do

dosomething1 && dosomething2 && dosomething3

Zatrzyma przetwarzanie, gdy jedno z poleceń powróci z niezerową wartością. Na przykład, następujące polecenie nigdy nie wyświetli "Gotowe":

cat nosuchfile && echo "done"
echo $?
1
 3
Author: gabor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-04 19:01:33
#!/bin/bash -e
Powinno wystarczyć.
 3
Author: Baligh Uddin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-24 13:14:14

Po prostu wrzuciłem jeszcze jeden dla odniesienia, ponieważ było dodatkowe pytanie do Mark Edgars input i tutaj jest dodatkowy przykład i dotyka tematu ogólnie:

[[ `cmd` ]] && echo success_else_silence

Czyli to samo co cmd || exit errcode Jak ktoś pokazał.

Np. Chcę się upewnić, że partycja jest odmontowana, jeśli jest zamontowana:

[[ `mount | grep /dev/sda1` ]] && umount /dev/sda1 
 -2
Author: Malina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-16 11:00:47