Saia Shell Script com base no processo Código de saída
Pergunta
Eu tenho um shell script que executa uma série de comandos. Como posso fazer a saída script shell se qualquer um a saída comandos com um código de saída diferente de zero?
Solução
Depois de cada comando, o código de saída pode ser encontrada na variável $?
assim que você teria algo como:
ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi
Você precisa ter o cuidado de comandos canalizada desde o $?
só lhe dá o código de retorno do último elemento no tubo assim, no código:
ls -al file.ext | sed 's/^/xx: /"
não retornará um código de erro se o arquivo não existe (desde a parte sed
do gasoduto realmente funciona, retornando 0).
O shell bash
realmente oferece uma variedade que pode ajudar nesse caso, que ser PIPESTATUS
. Esta matriz tem um elemento para cada um dos componentes de pipeline, que você pode acessar individualmente como ${PIPESTATUS[0]}
:
pax> false | true ; echo ${PIPESTATUS[0]}
1
Note que isso está ficando-lhe o resultado do comando false
, não todo o pipeline. Você também pode obter a lista inteira para o processo de como você vê o ajuste:
pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1
Se você quiser obter o maior código de erro de um oleoduto, você poderia usar algo como:
true | true | false | true | false
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done
echo $rc
Este passa por cada um dos elementos PIPESTATUS
, por sua vez, armazenando-o em rc
se fosse maior que o valor rc
anterior.
Outras dicas
Se você quiser trabalhar com $ ?, você precisa verificar isso após cada comando, desde $? é atualizado após cada comando saídas. Isto significa que se você executar um gasoduto, você só vai conseguir o código de saída do último processo no pipeline.
Outra abordagem é fazer isso:
set -e
set -o pipefail
Se você colocar isso no topo do shell script, parece que o bash irá cuidar do presente para você. Como um cartaz anterior observou, "set -e" fará com que o bash para sair com um erro em qualquer comando simples. "Conjunto pipefail -o" fará com que o bash para sair com um erro em qualquer comando em um oleoduto também.
aqui ou aqui para um pouco mais discussão sobre este problema. Aqui é a seção do manual do bash no set builtin.
"set -e
" é provavelmente a maneira mais fácil de fazer isso. Basta colocar que, antes de quaisquer comandos no seu programa.
Se você apenas chamar saída na festa sem parâmetros, ele irá retornar o código de saída do último comando. Combinado com OR a festa só deve invocar saída, se o comando anterior falhar. Mas eu não testei isso.
command1 || exit; command2 || exit;
O Bash também irá armazenar o código de saída do último comando na variável $ ?.
[ $? -eq 0 ] || exit $?; # exit for none-zero return code
http://cfaj.freeshell.org/shell/cus- faq-2.html # 11
-
Como faço para obter o código de saída do
cmd1
emcmd1|cmd2
Primeiro, observe que o código de saída
cmd1
poderia ser diferente de zero e ainda não significa um erro. Isso acontece por exemplo emcmd | head -1
Você pode observar um 141 (ou 269 com ksh93) status de saída
cmd1
, mas é porquecmd
foi interrompida por um sinal SIGPIPE quandohead -1
terminada depois de ter lido uma linha.Para saber o estado de saída dos elementos de um oleoduto
cmd1 | cmd2 | cmd3
a. com zsh:
Os códigos de saída são fornecidos na matriz pipestatus especial. código de saída
cmd1
está em$pipestatus[1]
, código de saídacmd3
em$pipestatus[3]
, de modo que$?
é sempre a mesma$pipestatus[-1]
.b. com bash:
Os códigos de saída são fornecidos na matriz
PIPESTATUS
especial. código de saídacmd1
está em${PIPESTATUS[0]}
, código de saídacmd3
em${PIPESTATUS[2]}
, de modo que$?
é sempre a mesma${PIPESTATUS: -1}
....
Para mais detalhes veja o seguinte ligação .
para bash:
# this will trap any errors or commands with non-zero exit status
# by calling function catch_errors()
trap catch_errors ERR;
#
# ... the rest of the script goes here
#
function catch_errors() {
# do whatever on errors
#
#
echo "script aborted, because of errors";
exit 0;
}
No bash isso é fácil, apenas amarrá-los juntos com &&:
command1 && command2 && command3
Você também pode usar o if aninhadas construção:
if command1
then
if command2
then
do_something
else
exit
fi
else
exit
fi
#
#------------------------------------------------------------------------------
# run a command on failure exit with message
# doPrintHelp: doRunCmdOrExit "$cmd"
# call by:
# set -e ; doRunCmdOrExit "$cmd" ; set +e
#------------------------------------------------------------------------------
doRunCmdOrExit(){
cmd="$@" ;
doLog "DEBUG running cmd or exit: \"$cmd\""
msg=$($cmd 2>&1)
export exit_code=$?
# if occured during the execution exit with error
error_msg="Failed to run the command:
\"$cmd\" with the output:
\"$msg\" !!!"
if [ $exit_code -ne 0 ] ; then
doLog "ERROR $msg"
doLog "FATAL $msg"
doExit "$exit_code" "$error_msg"
else
#if no errors occured just log the message
doLog "DEBUG : cmdoutput : \"$msg\""
doLog "INFO $msg"
fi
}
#eof func doRunCmdOrExit