Sair de um script com erro


141

Estou criando um Shell Script que tem uma iffunção como esta:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables
fi

...

Quero que a execução do script termine depois de exibir a mensagem de erro. Como posso fazer isso?

Respostas:


137

Você está procurando exit?

Este é o melhor guia do bash. http://tldp.org/LDP/abs/html/

No contexto:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables 1>&2
    exit 1 # terminate and indicate error
fi

...

5
Se você gosta do ABS, vai adorar o BashGuide , BashFAQ e BashPitfalls .
Pausado até novo aviso.

Esses links Bash são INCRÍVEIS! O BashFAQ estaria melhor posicionado como BashRecipes.
Pete Alvin

337

Se você colocar set -e um script, o script será encerrado assim que qualquer comando dentro dele falhar (ou seja, assim que qualquer comando retornar um status diferente de zero). Isso não permite que você escreva sua própria mensagem, mas geralmente as próprias mensagens do comando com falha são suficientes.

A vantagem dessa abordagem é que ela é automática: você não corre o risco de esquecer de lidar com um caso de erro.

Os comandos cujo status é testado por uma condicional (como if, &&ou ||) não encerram o script (caso contrário, a condicional seria inútil). Um idioma para o comando ocasional cuja falha não importa é command-that-may-fail || true. Você também pode set -edesativar uma parte do script com set +e.


3
De acordo com mywiki.wooledge.org/BashFAQ/105 - esse recurso tem um histórico de ser obscuro e complicado na determinação de quais códigos de erro dos comandos causam uma saída automática. Além disso, "as regras mudam de uma versão do Bash para outra, pois o Bash tenta rastrear a definição POSIX extremamente escorregadia desse 'recurso'". Concordo com @Dennis Williamson e a resposta aceita de stackoverflow.com/questions/19622198/… - use o erro trap trap 'error_handler'. Mesmo que seja uma armadilha!
Bondolin

3
geralmente o uso do -xsinalizador -eé suficiente para rastrear onde o programa está saindo. Isso implica que o usuário do script também é o desenvolvedor.
25416 Alex

Bom, mas acho que o OP precisava sair do script de uma exceção auto-definida.
vdegenne 27/01

42

Se você deseja lidar com um erro em vez de sair às cegas, em vez de usar set -e, use a trapno ERRpseudo sinal.

#!/bin/bash
f () {
    errorCode=$? # save the exit code as the first thing done in the trap function
    echo "error $errorCode"
    echo "the command executing at the time of the error was"
    echo "$BASH_COMMAND"
    echo "on line ${BASH_LINENO[0]}"
    # do some error handling, cleanup, logging, notification
    # $BASH_COMMAND contains the command that was being executed at the time of the trap
    # ${BASH_LINENO[0]} contains the line number in the script of that command
    # exit the script or return to try again, etc.
    exit $errorCode  # or use some other value or do return instead
}
trap f ERR
# do some stuff
false # returns 1 so it triggers the trap
# maybe do some other stuff

Outras armadilhas podem ser configuradas para lidar com outros sinais, incluindo os sinais usuais do Unix mais os outros pseudo-sinais do Bash RETURNe DEBUG.


8

Aqui está o caminho para fazê-lo:

#!/bin/sh

abort()
{
    echo >&2 '
***************
*** ABORTED ***
***************
'
    echo "An error occurred. Exiting..." >&2
    exit 1
}

trap 'abort' 0

set -e

# Add your script below....
# If an error occurs, the abort() function will be called.
#----------------------------------------------------------
# ===> Your script goes here
# Done!
trap : 0

echo >&2 '
************
*** DONE *** 
************
'

Por que a mensagem CONCLUÍDA para stderr?
Matt Bianco

1
Essa é uma prática comum, para que você possa canalizar a saída do script para o stdout, para que outro processo possa obtê-la sem ter as mensagens informativas no meio.
Supercobra

2
Provavelmente, é igualmente prática comum tratar qualquer coisa no stderr como uma indicação de problemas.
Matt Bianco

1
No passado, 'set -e' sempre funcionou para mim, mas hoje à noite me deparei com uma situação em uma imagem do Alpine Linux Docker em que não tinha efeito. Essa solução funcionou para mim e me colocou de volta na tarefa em questão. Muito apreciado.
Synthesizerpatel

@supercobra Prática comum? Onde?
Thorbjørn Ravn Andersen

-8

exit 1é tudo o que você precisa. O 1é um código de retorno, portanto você pode alterá-lo se desejar, digamos, 1significar uma execução bem-sucedida e -1significar uma falha ou algo parecido.


13
No unix, o sucesso é sempre 0. Isso pode ajudar ao usar testou &&ou ||.
Mouviciel

5
Para expandir o comentário do mouviciel: nos scripts de shell, 0 sempre significa sucesso e 1 a 255 significa falha. -1 está fora do intervalo (e geralmente terá o mesmo efeito que 255, portanto, uma falha como 1).
Gilles 'SO- stop be evil'

@mouviciel, @Gilles: Obrigado pela informação extra. Já faz um tempo desde que lidei com o bash.
DGH

Este é um mau exemplo de uso do código de retorno, caso contrário, seria uma ótima resposta.
Brad Koch

1
Além de recomendar incorretamente 1 para o sucesso, -1 não é possível (os códigos de saída não são assinados).
tripleee
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.