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

时间:2008-09-18 06:03:48

标签: bash shell

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

9 个答案:

答案 0 :(得分:467)

在每个命令之后,可以在$?变量中找到退出代码,这样你就可以得到:

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

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

ls -al file.ext | sed 's/^/xx: /"
如果文件不存在,

将不会返回错误代码(因为管道的sed部分实际工作,返回0)。

bash shell实际上提供了一个可以在这种情况下提供帮助的数组,即PIPESTATUS。此数组为每个管道组件都有一个元素,您可以单独访问,如${PIPESTATUS[0]}

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

请注意,这是获取false命令的结果,而不是整个管道。您还可以根据需要获取整个列表:

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

如果您想从管道中获取最大的错误代码,可以使用以下内容:

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

依次遍历每个PIPESTATUS元素,如果它大于之前的rc值,则将其存储在rc中。

答案 1 :(得分:213)

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

另一种方法是:

set -e
set -o pipefail

如果你把它放在shell脚本的顶部,看起来bash会为你处理这个问题。正如之前的一张海报所指出的那样,“set -e”会导致bash在任何简单命令上都出错。 “set -o pipefail”也会导致bash退出,并且管道中的任何命令都会出错。

有关此问题的更多讨论,请参阅herehereHere是set builtin上的bash手册部分。

答案 2 :(得分:50)

set -e”可能是最简单的方法。只需将它放在程序中的任何命令之前。

答案 3 :(得分:28)

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

command1 || exit;
command2 || exit;

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

答案 4 :(得分:25)

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

答案 5 :(得分:21)

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

  1. 如何在cmd1

    中获取cmd1|cmd2的退出代码

    首先,请注意cmd1退出代码可能不为零,但仍然没有 意味着错误。例如在

    中就会发生这种情况
    cmd | head -1
    

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

    了解管道元素的退出状态 cmd1 | cmd2 | cmd3

    一个。用zsh:

    退出代码在pipestatus特殊数组中提供。    cmd1退出代码位于$pipestatus[1]cmd3退出代码中    $pipestatus[3]$?始终与$pipestatus[-1]相同    PIPESTATUS

    湾用bash:

    退出代码在cmd1特殊数组中提供。    ${PIPESTATUS[0]}退出代码位于cmd3${PIPESTATUS[2]}退出代码中    $?${PIPESTATUS: -1}始终与{{1}}相同    {{1}}。

    ...

    有关详细信息,请参阅以下link

答案 6 :(得分:19)

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

答案 7 :(得分:11)

在bash中,这很简单,只需将它们与&&:

绑在一起即可
command1 && command2 && command3

您还可以使用嵌套的if结构:

if command1
   then
       if command2
           then
               do_something
           else
               exit
       fi
   else
       exit
fi

答案 8 :(得分:4)

#
#------------------------------------------------------------------------------
# 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