退出基于进程退出代码的Shell脚本

我有一个执行许多命令的shell脚本。 如果任何命令以非零退出代码退出,如何退出shell脚本?

在每个命令之后,可以在$?find退出代码$? variables,所以你会有这样的事情:

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

你需要小心pipe道命令,因为$? 只给你pipe道中最后一个元素的返回代码,所以在代码中:

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

如果文件不存在,将不会返回错误代码(因为stream水线的sed部分实际上工作,返回0)。

bash shell实际上提供了一个数组,可以协助这种情况,即PIPESTATUS 。 这个数组对于每个pipe道组件都有一个元素,您可以像${PIPESTATUS[0]}一样单独访问:

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

请注意,这是得到你的false命令的结果,而不是整个pipe道。 你也可以得到整个列表来处理你认为合适的:

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

如果你想从pipe道中获得最大的错误代码,你可以使用如下的东西:

 true | true | false | true | false rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done echo $rc 

如果它大于先前的rc值,则依次通过每个PIPESTATUS元素,将其存储在rc

如果你想使用$?,你需要在每个命令后检查它,因为$? 在每个命令退出后更新。 这意味着如果你执行一个pipe道,你将只能得到pipe道中最后一个进程的退出代码。

另一种方法是做到这一点:

 set -e set -o pipefail 

如果你把它放在shell脚本的顶部,它看起来像bash将为你照顾这个。 正如前面的海报所指出的那样,“set -e”会导致bash在任何简单的命令中出错并退出。 “set -o pipefail”会导致bash在pipe道中的任何命令上出错并退出。

看到这里或这里多一点关于这个问题的讨论。 这里是内置的bash手册部分。

set -e ”可能是最简单的方法。 只要把你的程序中的任何命令之前。

如果你只是在没有参数的bash中调用exit,它将返回最后一个命令的退出代码。 与OR相结合,如果前面的命令失败,bash只能调用exit。 但是我没有testing过这个。

 command1 || 出口;
 command2 || 出口;

Bash还会将最后一个命令的退出代码存储在variables$?中。

http://cfaj.freeshell.org/shell/cus-faq-2.html#11

  1. 如何在cmd1|cmd2获取cmd1的退出码

    首先,请注意, cmd1退出代码可能不为零,但仍然不代表错误。 这发生在例如

     cmd | head -1 

    您可能会观察到cmd1的141(或ksh93的269)退出状态,但这是因为当读取一行后, head -1终止时, cmd被SIGPIPE信号中断。

    要知道pipe道cmd1 | cmd2 | cmd3的元素的退出状态 cmd1 | cmd2 | cmd3

    一个。 用zsh:

    退出代码在pipestatus特殊数组中提供。 cmd1退出代码在$pipestatus[1]cmd3退出代码在$pipestatus[3] ,这样$? 总是和$pipestatus[-1]

    湾 与bash:

    退出代码在PIPESTATUS特殊数组中提供。 cmd1退出代码在${PIPESTATUS[0]}cmd3退出代码在${PIPESTATUS[2]} ,这样$? 总是和${PIPESTATUS: -1}

    欲了解更多详情,请参阅以下链接 。

 [ $? -eq 0 ] || exit $?; # exit for none-zero return code 

为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; } 

在bash中,这很容易,只要把它们和&&结合在一起:

 command1 && command2 && command3 

你也可以使用嵌套的if结构:

 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