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

有帮助吗?

解决方案

在每个命令之后,可以在以下位置找到退出代码: $? 变量,所以你会得到类似的东西:

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 价值。

其他提示

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

另一种方法是这样做:

set -e
set -o pipefail

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

这里 或者 这里 关于这个问题的更多讨论。 这里 是内置集上的 bash 手册部分。

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

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

command1 || exit;
command2 || exit;

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

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

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

  1. 我如何获得退出代码 cmd1cmd1|cmd2

    首先,请注意 cmd1 退出代码可能是非零的,但仍然并不意味着错误。例如,这种情况发生在

    cmd | head -1
    

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

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

    A。使用 zsh:

    退出代码在 pipelinestatus 特殊数组中提供。 cmd1 退出代码位于 $pipestatus[1], cmd3 退出代码在 $pipestatus[3], , 以便 $? 总是一样 $pipestatus[-1].

    b.与bash:

    退出代码在 PIPESTATUS 特殊阵列。 cmd1 退出代码位于 ${PIPESTATUS[0]}, cmd3 退出代码在 ${PIPESTATUS[2]}, , 以便 $? 总是一样 ${PIPESTATUS: -1}.

    ...

    欲了解更多详情,请参阅以下内容 关联.

对于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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top