暗无天日

=============>DarkSun的个人博客

Bash中的TryCatch语句

Bash 中是没有原生的Try Catch 语句的,但是今天从 https://www.xmodulo.com/catch-handle-errors-bash.html 上我看到了一种模拟 Try Catch 的方法。

函数定义如下(经过了一些改造,更好理解一些,而且原文是有一点小错误的):

function try()
{
    if [[ $SHELLOPTS = *errexit* ]];then      # $SHELLOPTS 中包含了 shell 的配置项
       ERREXIT_P="Y"                          # 保存ERREXIT的启用情况
       set +e                                 # 若开启了ERREXIT则需要关闭该配置项,否则后面throw()返回非0值时会直接终止代码运行,也就没法运行后面的catch()语句了
    fi
}

function throw()
{
    exit $1
}

function catch()
{
    export exception_code=$?
    if [[ ${ERREXIT_P} == "Y" ]];then
     set -e                     # 恢复原ERREXIT配置项
    fi
    return $exception_code
}

这套函数的使用方法如下例子所示:

# 引入 trycatch 语句
source ./trycatch.sh

# 定义异常类型
export ERR_BAD=100
export ERR_WORSE=101
export ERR_CRITICAL=102

try
(                               # 注意这里进入子shell执行命令
    echo "Start of the try block"

    # 当命令执行出错(返回非0值),则throw 会退出子shell 的执行,并返回异常.
    run-command || throw $ERR_BAD
    run-command2 || throw $ERR_WORSE
    run-command3 || throw $ERR_CRITICAL

    echo "End of the try block"
)
catch || {                      # 若子shell执行有异常,则执行后面 {} 中的语句
    case $exception_code in     # exception_code 中存放的是子 shell 的返回值,在有异常的情况下也就是throw 出来的异常码
        $ERR_BAD)
            echo "This error is bad"
        ;;
        $ERR_WORSE)
            echo "This error is worse"
        ;;
        $ERR_CRITICAL)
            echo "This error is critical"
        ;;
        *)
            echo "Unknown error: $exit_code"
            throw $exit_code    # re-throw an unhandled exception
        ;;
    esac
}

这套TryCatch模拟语句最大的坑莫过于 try 的语句是在子shell 中执行了,这使得 try 中的执行内容无法修改其他代码块中的变量。