Mam skrypt bash, który używa, set -o errexit
więc po błędzie cały skrypt kończy się w momencie awarii.
Skrypt uruchamia curl
polecenie, które czasami nie może pobrać zamierzonego pliku - jednak gdy to nastąpi, skrypt nie kończy błędu.
Dodałem for
pętlę do
- zatrzymaj się na kilka sekund, a następnie ponów
curl
komendę - użyj
false
na dole pętli for, aby zdefiniować domyślny niezerowy status wyjścia - jeśli polecenie curl się powiedzie - pętla się zepsuje, a status wyjścia ostatniego polecenia powinien wynosić zero.
#! /bin/bash
set -o errexit
# ...
for (( i=1; i<5; i++ ))
do
echo "attempt number: "$i
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
if [ -f ~/.vim/autoload/pathogen.vim ]
then
echo "file has been retrieved by curl, so breaking now..."
break;
fi
echo "curl'ed file doesn't yet exist, so now will wait 5 seconds and retry"
sleep 5
# exit with non-zero status so main script will errexit
false
done
# rest of script .....
Problem polega na tym, że gdy curl
polecenie się nie powiedzie, pętla ponawia polecenie pięć razy - jeśli wszystkie próby zakończą się niepowodzeniem, pętla for kończy się, a skrypt główny jest wznawiany - zamiast wyzwalania errexit
.
Jak sprawić, by cały skrypt zakończył działanie, jeśli curl
instrukcja się nie powiedzie?
źródło
true
przed instrukcją break, aby była jawna i zapewniła wartość wyjściową pętli?exit 1
kiedy po prostuexit
zadziałałoby. Jest to jednak kwestia stylu, a inni mogą mieć własne opinie.exit
jako zwykłe wyjście - to samo kończy skrypt.exit 1
czytałby mi jako „sygnał” do jakiegoś innego procesu (tj.errexit
) - że powinien on zakończyć skrypt na podstawie „wyniku”exit 1
. - więc poszedłem z,exit
ale dziękuję za wyjaśnienieexit 1
. To w ogóle nie wpływaerrexit
. Mówi jedynie programowi wywołującemu, że coś poszło nie tak.false
Polecenie zawiera jedno stwierdzenie:exit(1)
. 99,9% poleceń Uniksa zwraca 0 w przypadku powodzenia i niezerowe w przypadku błędu. Twoje też powinny.Jeśli
errexit
ustawiłeś, tofalse
instrukcja powinna spowodować natychmiastowe zakończenie skryptu. To samo, jeślicurl
polecenie się nie powiedzie.Twój przykładowy skrypt, jak napisano, powinien wyjść po
curl
niepowodzeniu pierwszego polecenia przy pierwszym wywołaniu,false
jeśli ustawiony jest errexit.Aby zobaczyć, jak to działa (używam skrótu,
-e
aby ustawićerrexit
:Jeśli więc
curl
polecenie zostanie wykonane więcej niż raz, ten skrypt nie zostanieerrexit
ustawiony.źródło
set -e
jest bardziej subtelny. To będzie nie wyjść po pierwszej nieudanej polecenia w pętli. Możesz to sobie udowodnić, uruchamiając(set -e; for (( i=1; i<5; i++ )); do echo $i; false; done || echo "FAIL"; )
i zauważając, że kod działafalse
cztery razy. Aby uzyskać więcej informacjiset -e
, zobacz Greg's FAQ # 105 .errexit
nie ma dowodów . Zastosuj logikę do skryptu w pytaniu. Uruchom to:(set -e; for (( i=1; i<5; i++ )); do echo $i; false; done ; echo still here )
tak testowanie zwracanych wartości za pomocąif
while
||
&&
etc nie wyzwala errexit. Oryginalny skrypt nie zawierał||
pętli for.set -o errexit
polecenia w moim przykładowym kodzie, dodałem je teraz - i dla mnie nie było błędu wyjścia zgodnie z oczekiwaniami. Musiałem zachowaćfalse
ostatnią komendę w pętli for, a następnie zamknąć pętlę za pomocądone || exit [1]
- wtedy działało to ładnie!set -o errexit
może być trudne w pętlach i podpowłokach, ponieważ musisz przejść z powrotem przez proces.Zerwanie pętli (nawet podczas normalnej pracy) jest uważane za złą praktykę. Możesz zadzwonić do mnie oldschool, że wolę pętlę while zamiast pętli for dla dwóch warunków, ale uważam, że lepiej jest przeczytać:
źródło
Jeśli
errexit
jest ustawiony, acurl
polecenie nie powiedzie się, skrypt kończy się zaraz po nieudanym poleceniu curl. W podręczniku bash nie ma podpowiedzi, któraset -e
ignoruje wszelkie nieudane zwroty pojedynczego polecenia złożonego. Byłoby tak tylko w przypadku, gdy polecenie złożone jest wykonywane w kontekście, w którymset -e
jest ignorowane.https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin
Spróbuj nieco zaadaptowanego przykładu opublikowanego przez RobertL. To kończy się przy pierwszej iteracji zaraz po fałszywym poleceniu:
źródło
Możesz po prostu dodać opcję --fail do polecenia curl, to rozwiąże problem, skrypt zakończy się niepowodzeniem i zakończy działanie po błędzie, jeśli polecenie curl się nie powiedzie, jeśli jest to bardzo przydatne, gdy używasz curl w potoku Jenkinsa:
źródło