Sair do script de shell com base no código de saída do processo

Eu tenho um script de shell que executa vários comandos. Como eu faço o script de shell sair se algum dos comandos sair com um código de saída diferente de zero?

Após cada comando, o código de saída pode ser encontrado no $? variável, então você teria algo como:

 ls -al file.ext rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi 

Você precisa ter cuidado com os comandos canalizados desde o $? só lhe dá o código de retorno do último elemento no pipe, então, no código:

 ls -al file.ext | sed 's/^/xx: /" 

não retornará um código de erro se o arquivo não existir (desde que a parte sed do pipeline realmente funcione, retornando 0).

O shell bash , na verdade, fornece uma matriz que pode ajudar nesse caso, sendo PIPESTATUS . Esta matriz tem um elemento para cada um dos componentes do pipeline, que você pode acessar individualmente, como ${PIPESTATUS[0]} :

 pax> false | true ; echo ${PIPESTATUS[0]} 1 

Observe que isso está gerando o resultado do comando false , não o pipeline inteiro. Você também pode obter toda a lista para processar como achar melhor:

 pax> false | true | false; echo ${PIPESTATUS[*]} 1 0 1 

Se você quisesse obter o maior código de erro de um pipeline, 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 

Isso passa por cada um dos elementos PIPESTATUS , por sua vez, armazenando-o em rc se for maior que o valor rc anterior.

Se você quer trabalhar com $ ?, você precisará verificar depois de cada comando, desde $? é atualizado após cada comando sair. Isso significa que, se você executar um pipeline, somente obterá 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 script de shell, parece que o bash vai cuidar disso para você. Como um poster anterior observou, “set -e” fará com que o bash saia com um erro em qualquer comando simples. “set -o pipefail” fará com que o bash saia com um erro em qualquer comando em um pipeline também.

Veja aqui ou aqui para um pouco mais de discussão sobre este problema. Aqui está a seção manual do bash no set builtin.

set -e ” é provavelmente a maneira mais fácil de fazer isso. Basta colocar isso antes de qualquer comando no seu programa.

Se você acabou de chamar exit no bash sem parâmetros, ele retornará o código de saída do último comando. Combinado com OR, o bash só deve chamar exit, se o comando anterior falhar. Mas eu não testei isso.

 comando1 ||  Saída;
 comando2 ||  Saída;

O Bash também 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

  1. Como obtenho o código de saída de cmd1 em cmd1|cmd2

    Primeiro, observe que o código de saída cmd1 pode ser diferente de zero e ainda não significa um erro. Isso acontece, por exemplo, em

     cmd | head -1 

    você pode observar um status de saída 141 (ou 269 com ksh93) de cmd1 , mas é porque o cmd foi interrompido por um sinal SIGPIPE quando a head -1 terminou após ter lido uma linha.

    Para saber o status de saída dos elementos de um pipeline cmd1 | cmd2 | cmd3 cmd1 | cmd2 | cmd3

    uma. com zsh:

    Os códigos de saída são fornecidos no array especial pipestatus. cmd1 código de saída cmd1 está em $pipestatus[1] , o código de saída cmd3 em $pipestatus[3] , de forma que $? é sempre o mesmo que $pipestatus[-1] .

    b. com bash:

    Os códigos de saída são fornecidos no array especial do PIPESTATUS . cmd1 código de saída cmd1 está em ${PIPESTATUS[0]} , o código de saída cmd3 em ${PIPESTATUS[2]} , de modo que $? é sempre o mesmo que ${PIPESTATUS: -1} .

    Para mais detalhes, veja o link a seguir.

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 amarre-os com o &&:

 command1 && command2 && command3 

Você também pode usar a construção if aninhada:

 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