关于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

    推荐阅读

      linux命令补全工具?

      linux命令补全工具?,工具,系统,软件,地址,命令,名称,智能,环境,信息,终端,简

      linux如何引入命令?

      linux如何引入命令?,单位,系统,首页,名字,命令,终端,音乐,文件,目录,选项,lin

      linux关闭系统的命令?

      linux关闭系统的命令?,系统,工作,命令,时间,用户,指令,通知,目的,终端,表示,

      linux命令出现箭头?

      linux命令出现箭头?,系统,终端,箭头,等级,网络,状态,情况,首页,第一,命令,在l

      linux组播路由命令?

      linux组播路由命令?,网络,信息,地址,系统,通信,工具,命令,服务,数字,控制台,L

      更新文件命令linux?

      更新文件命令linux?,工作,系统,地址,信息,时间,命令,目录,基础,标准,网络,lin

      linux切换目标命令?

      linux切换目标命令?,系统,密码,工具,命令,一致,工作,用户,终端,目录,用户名,l

      linux系统nl命令?

      linux系统nl命令?,系统,工作,命令,信息,文件,标准,工具,单位,公式,内容,nl是

      aix与linux的命令?

      aix与linux的命令?,系统,信息,命令,时间,管理,设备,平台,环境,地址,电脑,给些

      linux命令删除用户组?

      linux命令删除用户组?,管理,密码,系统,用户组,用户,概念,命令,文件,管理员,

      linux运行图形界命令?

      linux运行图形界命令?,系统,密码,地址,电脑,图形界面,地方,工具,界面,终端,

      linux怎样运行命令?

      linux怎样运行命令?,系统,工作,信息,基础,地址,命令,目录,工具,密码,一致,Lin

      linux移动文档命令?

      linux移动文档命令?,文件,名称,系统,位置,目录,信息,命令,源文件,目标,文件

      光盘挂载linux命令?

      光盘挂载linux命令?,系统,数据,设备,盘中,光盘,通用,命令,文件,目录,虚拟机,

      linux里生产常用命令?

      linux里生产常用命令?,工作,地址,系统,信息,生产,命令,目录,网络,管理,标准,l

      linux命令中的作用?

      linux命令中的作用?,系统,网络,地址,管理,信息,服务,软件,工具,命令,通用,lin

      纯命令行linux服务器?

      纯命令行linux服务器?,密码,服务,系统,命令,终端,地址,百度,情况,状态,公共,

      linux命令升级内核?

      linux命令升级内核?,系统,软件,电脑,发行,最新,内核,情况,官网,状态,材料,Lin

      linux怎样中断命令?

      linux怎样中断命令?,服务,系统,状态,名称,进程,管理,工具,信息,电脑,传播,Lin