Jak wyjść ze skryptu powłoki, jeśli jedna jego część zawiedzie?

Jak napisać skrypt powłoki, który kończy działanie, jeśli jedna z jego części zawiedzie? Na przykład, jeśli poniższy fragment kodu zawiedzie, skrypt powinien się zakończyć.

n=0 until [ $n -ge 5 ] do gksu *command* && break n=$[$n+1] sleep 3 

Odpowiedź

Jednym ze sposobów byłoby dodanie set -e na początku skryptu. To znaczy (z help set):

 -e Exit immediately if a command exits with a non-zero status. 

Więc jeśli którekolwiek z poleceń zakończy się niepowodzeniem, skrypt zakończy działanie.

Alternatywnie możesz dodać jawne instrukcje exit w miejscach możliwych błędów:

command || exit 1 

Komentarze

  • Ja (i wiki bash ) wolę, aby ludzie zastanowili się nad prawidłową obsługą błędów zamiast używać funkcji (zepsutej przez projekt IMO) set -e. Jednak nie ' nie ma tutaj zastosowania. OP chce wyjść ze skryptu po 5 nieudanych próbach wykonania polecenia.
  • @St é phaneChazelas Wygrałem ' nie kłócę się z tobą o to, czy ' jest uszkodzony, ja ' na pewno ' re right. Jednak OP zapytał " Jak mogę napisać skrypt powłoki, który kończy działanie, jeśli jedna jego część zawiedzie? ", co sprawia, że czy myślisz, że ' kończy się po 5 błędach?
  • ponieważ mogę ' nie myśleć o żadnym innym pytanie może zostać zinterpretowane.
  • @St é phaneChazelas możesz mieć rację. Zinterpretowałem to dosłownie: w jaki sposób cały skrypt może się zakończyć, jeśli jakakolwiek jego część zawiedzie. A set -e to jedyny sposób, w jaki mogę to zrobić.
  • W tym fragmencie skryptu polecenia, które mogą wywołać set -e to sleep (break to specjalne wbudowane polecenie, które spowodowałoby zamknięcie skryptu w przypadku awarii w większości powłok, polecenia w iv id = set -e, n=... lub po lewej stronie &&

może się nie powieść, jeśli n jest tylko do odczytu, ale wtedy skrypt zakończy się bez set -e), więc interpretacja brzmi dość mało prawdopodobne. Zgadzam się, że pytanie jest źle sformułowane.

Odpowiedź

Możesz zamknąć skrypt w dowolnym miejscu, używając słowa kluczowego exit. Możesz również określić kod zakończenia, aby wskazać innym programom, że lub jak Twój skrypt zawiódł, np. exit 1 lub exit 2 itd. (Zgodnie z konwencją kod zakończenia 0 oznacza sukces, a wartości większe niż 0 oznaczają porażkę; jednak również zgodnie z konwencją , kody wyjścia powyżej 127 są zarezerwowane dla nieprawidłowego zakończenia (np. przez sygnał)).

Ogólna konstrukcja wyjścia w przypadku niepowodzenia to

if [ failure condition ]; then exit n fi 

z odpowiednimi failure condition i n. Ale w określonych sytuacjach możesz postępować inaczej. Teraz w twoim przypadku interpretuję twoje pytanie, że jeśli którekolwiek z pięciu wywołań gksu nie powiedzie się, masz zamiar wyjść. Jednym ze sposobów jest użycie funkcji takiej jak ta

function try_command { for i in 1 2 3 4 5 ; do if gksu command ; then return 0 fi fi exit 1 } 

, a następnie wywołanie pętli przez try_command.

Istnieją (bardziej) zaawansowane lub wyrafinowane sposoby odpowiedzi na Twoje pytanie. Jednak powyższe rozwiązanie jest bardziej dostępne dla początkujących niż, powiedzmy, rozwiązanie Stephanea.

Odpowiedź

attempt=0 until gksu command; do attempt=$((attempt + 1)) if [ "$attempt" -gt 5 ]; then exit 1 fi done 

exit kończy działanie skryptu, chyba że zostanie wywołany w podpowłoce. Jeśli ta część skryptu znajduje się w podpowłoce, na przykład ponieważ znajduje się ona w obrębie (...) lub $(...) lub jest częścią rurociągu , to opuści tylko tę podpowłokę .

W takim przypadku, jeśli chcesz, aby skrypt zakończył działanie jako dodatek do podpowłoki, to ” Muszę wywołać exit po zamknięciu tej podpowłoki.

Na przykład tutaj z dwoma zagnieżdżonymi poziomami podpowłok:

( life=hard output=$( echo blah [ "$life" = easy ] || exit 1 # exit subshell echo blih not run ) || exit # if the subshell exits with a non-zero exit status, # exit as well with the same exit status echo not run either ) || exit # if the subshell exits with a non-zero exit status, # exit as well with the same exit status 

Może się to stać trudniejsze, jeśli podpowłoka jest częścią potoku. bash ma specjalną tablicę $PIPESTATUS, podobną do zsh „s $pipestatus taki, który może Ci tutaj pomóc:

{ echo foo exit 1 echo bar } | wc -c subshell_ret=${PIPESTATUS[0]} if [ "$subshell_ret" -ne 0 ]; then exit "$subshell_ret" fi 

Odpowiedź

Pułapka wykona akcję po odebraniu sygnału.

trap "echo EXIT; exit" 0 trap "echo HUP; exit" 1 trap "echo CTL-C; exit" 2 trap "echo QUIT; exit" 3 trap "echo ERR; exit" ERR n=0 until [ $n -ge 5 ] do n=$[$n+1] echo $n sleep 3 done 

Uruchom to i pozwól mu normalnie wyjść. Zatrzymuje się na sygnale 0.

EXIT 

Uruchom go ponownie i przerwij za pomocą ^ C. Przechwytuje zarówno sygnał 2, jak i sygnał 0.

CTL-C EXIT 

Niezerowy status wyjścia będzie pułapki na ERR

ERR EXIT 

Odpowiedź

pass_to_functio() { echo "command exited with status $1" } ( exec <Any Command > & child_pid=$! wait $child_pid pass_to_function $? )& 

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *