当前位置:首页> 正文

关于bash:基于Process Exit Code退出Shell脚本

关于bash:基于Process Exit Code退出Shell脚本

Exit Shell Script Based on Process Exit Code

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


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

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

您需要注意管道命令,因为$?只提供管道中最后一个元素的返回码,因此,在代码中:

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

如果文件不存在,则不会返回错误代码(因为管道的sed部分实际工作,返回0)。

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

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

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

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

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

1
2
3
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
2
set -e
set -o pipefail

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

请参阅此处或此处以获取有关此问题的更多讨论。这是set builtin上的bash手册部分。


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


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

1
2
command1 || exit;
command2 || exit;

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


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

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

  • 如何在cmd1|cmd2中获取cmd1的退出代码

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

    1
    cmd | head -1

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

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

    一个。用zsh:

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

    湾用bash:

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

    ...

    有关详细信息,请参阅以下链接。


  • 对于bash:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 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中这很容易,只需用&&将它们绑在一起:

    1
    command1 && command2 && command3

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    if command1
       then
           if command2
               then
                   do_something
               else
                   exit
           fi
       else
           exit
    fi

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #
    #------------------------------------------------------------------------------
    # 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

    展开全文阅读

    相关内容