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?

Foi útil?

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

  1. Como faço para obter o código de saída do cmd1 em cmd1|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 em

    cmd | head -1
    

    Você pode observar um 141 (ou 269 com ksh93) status de saída cmd1, mas é porque cmd foi interrompida por um sinal SIGPIPE quando head -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ída cmd3 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ída cmd1 está em ${PIPESTATUS[0]}, código de saída cmd3 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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top