Eu tenho um script bash que usa set -o errexit
para que, por erro, o script inteiro saia no ponto de falha.
O script executa um curl
comando que às vezes falha ao recuperar o arquivo pretendido - no entanto, quando isso ocorre, o script não falha ao sair.
Eu adicionei um for
loop para
- pausar por alguns segundos e tente novamente o
curl
comando - use
false
na parte inferior do loop for para definir um status de saída diferente de zero - se o comando curl for bem-sucedido - o loop será interrompido e o status de saída do último comando deverá ser 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 .....
O problema é que quando o curl
comando falha, o loop tenta novamente o comando cinco vezes - se todas as tentativas forem malsucedidas, o loop for termina e o script principal é retomado - em vez de acionar o comando errexit
.
Como posso obter o script inteiro para sair se esta curl
declaração falhar?
fonte
true
antes da declaração de interrupção explícita e garantir o valor de saída do loop?exit 1
quando simplesmenteexit
funcionaria. É, porém, uma questão de estilo e outros podem ter suas próprias opiniões.exit
como uma saída simples - que encerra o script por si só.exit 1
leria para mim como um "sinal" para algum outro processo (ou sejaerrexit
) - que ele deveria finalizar o script com base no "resultado" deexit 1
. - então eu ter ido comexit
mas graças para explicaçãoexit 1
. Isso não afetaerrexit
nada. Simplesmente informa ao programa de chamada que algo deu errado. Ofalse
comando contém uma declaração:exit(1)
. 99,9% dos comandos Unix retornam 0 em caso de sucesso e diferente de zero em caso de erro. O seu também deveria.Se você
errexit
configurou, afalse
instrução deve fazer com que o script saia imediatamente. A mesma coisa se ocurl
comando falhou.Seu exemplo de script, conforme escrito, deve sair após a primeira
curl
falha de comando na primeira vez em que chamafalse
se errexit estiver definido.Para ver como funciona (eu uso a abreviação
-e
de para definirerrexit
:Portanto, se o
curl
comando executar mais de uma vez, esse script não foierrexit
definido.fonte
set -e
é mais sutil que isso. Ele não será fechado após o primeiro comando com falha em um loop. Você pode provar isso executando(set -e; for (( i=1; i<5; i++ )); do echo $i; false; done || echo "FAIL"; )
e observando que o código é executadofalse
quatro vezes. Para mais informaçõesset -e
, consulte o FAQ de Greg # 105 .errexit
não foram definidas. Por favor, aplique a lógica ao script na pergunta. Execute isto:(set -e; for (( i=1; i<5; i++ )); do echo $i; false; done ; echo still here )
Sim, testar valores de retorno comif
while
||
&&
etc não dispara errexit. O script original não apresentou||
o loop for.set -o errexit
comando no meu código de exemplo, o adicionei agora - e para mim não foi um erro ao sair conforme o esperado. Eu precisava manter ofalse
como o último comando no loop for, depois fechar o loop comdone || exit [1]
- então funcionou muito bem!set -o errexit
pode ser complicado em loops e sub-conchas, porque você precisa voltar ao processo.Quebrar um loop (mesmo em operação normal) é considerado uma má prática. Você pode me chamar de velha escola para preferir um loop while em vez de um loop for por duas condições, mas acho melhor ler:
fonte
Se
errexit
estiver definido e ocurl
comando falhar, o script será encerrado logo após o comando curl com falha. No manual do bash, não há dica queset -e
ignore qualquer status de retorno com falha de um único em um comando composto. Este seria apenas o caso se o comando composto for executado em um contexto ondeset -e
é ignorado.https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin
Experimente um exemplo ligeiramente adaptado publicado por RobertL. Isso para na primeira iteração logo após o comando false:
fonte
Você pode simplesmente adicionar a opção --fail ao comando curl, isso resolverá seu problema, o script falhará e sairá com erro se o comando curl falhar, se muito útil também ao usar curl no pipeline de jenkins:
fonte