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
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 $? )&
set -e
. Jednak nie ' nie ma tutaj zastosowania. OP chce wyjść ze skryptu po 5 nieudanych próbach wykonania polecenia.set -e
to jedyny sposób, w jaki mogę to zrobić.set -e
tosleep
(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&&