Como sair se um comando falhar?
-
26-09-2019 - |
Pergunta
Eu sou um noob em scripts de shell. Quero imprimir uma mensagem e sair do meu script se um comando falhar. Eu tentei:
my_command && (echo 'my_command failed; exit)
mas não funciona. Ele continua executando as instruções seguindo esta linha no script. Estou usando o Ubuntu e o Bash.
Solução
Tentar:
my_command || { echo 'my_command failed' ; exit 1; }
Quatro mudanças:
- Mudar
&&
para||
- Usar
{ }
no lugar de( )
- Introduzir
;
depoisexit
e - espaços depois
{
e antes}
Como você deseja imprimir a mensagem e sair apenas quando o comando falha (saídas com valor diferente de zero), você precisa de um ||
não um &&
.
cmd1 && cmd2
correrá cmd2
quando cmd1
é bem -sucedido (valor de saída 0
). Enquanto
cmd1 || cmd2
correrá cmd2
quando cmd1
falha (valor de saída diferente de zero).
Usando ( )
faz o comando dentro deles correr em um Sub-concha e chamando a exit
A partir daí, faz com que você saia da sub-concha e não do seu shell original, portanto, a execução continua no seu shell original.
Para superar este uso { }
As duas últimas alterações são exigidas pelo Bash.
Outras dicas
As outras respostas abordaram bem a pergunta direta, mas você também pode estar interessado em usar set -e
. Com isso, qualquer comando que falhe (fora de contextos específicos como if
testes) fará com que o script seja abortado. Para certos scripts, é muito útil.
Se você deseja esse comportamento para todos os comandos em seu script, basta adicionar
set -e
set -o pipefail
No início do script. Este par de opções informa ao intérprete Bash para sair sempre que um comando retornar com um código de saída diferente de zero.
No entanto, isso não permite imprimir uma mensagem de saída.
Observe também que o status de saída de cada comando é armazenado na variável shell $?, Que você pode verificar imediatamente após a execução do comando. Um status diferente de zero indica falha:
my_command
if [ $? -eq 0 ]
then
echo "it worked"
else
echo "it failed"
fi
Eu invadi o seguinte idioma:
echo "Generating from IDL..."
idlj -fclient -td java/src echo.idl
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi
echo "Compiling classes..."
javac *java
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi
echo "Done."
Preceder cada comando com um eco informativo e siga cada comando com o mesmo
if [ $? -ne 0 ];...
linha. (Claro, você pode editar essa mensagem de erro, se quiser.)
Forneceu my_command
é projetado canonicamente, ou seja retorna 0 quando é bem -sucedido, então &&
é exatamente o oposto do que você deseja. Você quer ||
.
Observe também isso (
Não me parece certo em Bash, mas não posso tentar de onde estou. Diga-me.
my_command || {
echo 'my_command failed' ;
exit 1;
}
Você também pode usar, se deseja preservar o status de erro de saída e ter um arquivo legível com um comando por linha:
my_command1 || exit $?
my_command2 || exit $?
Isso, no entanto, não imprimirá nenhuma mensagem de erro adicional. Mas, em alguns casos, o erro será impresso pelo comando falhado de qualquer maneira.
o trap
O Shell Builtin permite capturar sinais e outras condições úteis, incluindo a execução de comando com falha (ou seja, um status de retorno diferente de zero). Então, se você não quiser testar explicitamente o status de retorno de cada comando, você pode dizer trap "your shell code" ERR
e o código do shell será executado sempre que um comando retornar um status diferente de zero. Por exemplo:
trap "echo script failed; exit 1" ERR
Observe que, como em outros casos de captura de comandos falhados, os pipelines precisam de tratamento especial; O acima não vai pegar false | true
.
As funções a seguir apenas ecoam erros se um comando falhar:
silently () {
label="${1}"
command="${2}"
error=$(eval "${command}" 2>&1 >"/dev/null")
if [ ${?} -ne 0 ]; then
echo "${label}: ${error}" >&2
exit 1
fi
}