我正在写一个shell脚本,需要检查终端应用程序是否已安装。我想使用TRY/CATCH命令来做到这一点,除非有更整洁的方法。


当前回答

你可以:

#!/bin/bash
if <command> ; then # TRY
    <do-whatever-you-want>
else # CATCH
    echo 'Exception'
    <do-whatever-you-want>
fi

其他回答

Bash中有TRY CATCH命令吗?

不。

Bash不像在许多编程语言中那样拥有那么多奢侈的东西。

bash中没有try/catch;但是,可以使用&&或||实现类似的行为。

使用| |:

如果command1失败,则command2按如下方式运行

command1 || command2

类似地,使用&&,如果command1成功,command2将运行

try/catch最接近的近似如下

{ # try

    command1 &&
    #save your output

} || { # catch
    # save log for exception 
}

此外,bash还包含一些错误处理机制

set -e

如果任何简单的命令失败,它将停止脚本。

还有为什么不是if…else。它是你最好的朋友。

我已经在bash中开发了一个几乎完美无缺的try & catch实现,它允许您编写如下代码:

try 
    echo 'Hello'
    false
    echo 'This will not be displayed'

catch 
    echo "Error in $__EXCEPTION_SOURCE__ at line: $__EXCEPTION_LINE__!"

您甚至可以将try-catch块嵌套在它们自己内部!

try {
    echo 'Hello'

    try {
        echo 'Nested Hello'
        false
        echo 'This will not execute'
    } catch {
        echo "Nested Caught (@ $__EXCEPTION_LINE__)"
    }

    false
    echo 'This will not execute too'

} catch {
    echo "Error in $__EXCEPTION_SOURCE__ at line: $__EXCEPTION_LINE__!"
}

代码是bash样板文件/框架的一部分。它进一步扩展了try & catch的思想,例如使用回溯和异常进行错误处理(以及其他一些不错的特性)。

下面是负责try & catch的代码:

set -o pipefail
shopt -s expand_aliases
declare -ig __oo__insideTryCatch=0

# if try-catch is nested, then set +e before so the parent handler doesn't catch us
alias try="[[ \$__oo__insideTryCatch -gt 0 ]] && set +e;
           __oo__insideTryCatch+=1; ( set -e;
           trap \"Exception.Capture \${LINENO}; \" ERR;"
alias catch=" ); Exception.Extract \$? || "

Exception.Capture() {
    local script="${BASH_SOURCE[1]#./}"

    if [[ ! -f /tmp/stored_exception_source ]]; then
        echo "$script" > /tmp/stored_exception_source
    fi
    if [[ ! -f /tmp/stored_exception_line ]]; then
        echo "$1" > /tmp/stored_exception_line
    fi
    return 0
}

Exception.Extract() {
    if [[ $__oo__insideTryCatch -gt 1 ]]
    then
        set -e
    fi

    __oo__insideTryCatch+=-1

    __EXCEPTION_CATCH__=( $(Exception.GetLastException) )

    local retVal=$1
    if [[ $retVal -gt 0 ]]
    then
        # BACKWARDS COMPATIBILE WAY:
        # export __EXCEPTION_SOURCE__="${__EXCEPTION_CATCH__[(${#__EXCEPTION_CATCH__[@]}-1)]}"
        # export __EXCEPTION_LINE__="${__EXCEPTION_CATCH__[(${#__EXCEPTION_CATCH__[@]}-2)]}"
        export __EXCEPTION_SOURCE__="${__EXCEPTION_CATCH__[-1]}"
        export __EXCEPTION_LINE__="${__EXCEPTION_CATCH__[-2]}"
        export __EXCEPTION__="${__EXCEPTION_CATCH__[@]:0:(${#__EXCEPTION_CATCH__[@]} - 2)}"
        return 1 # so that we may continue with a "catch"
    fi
}

Exception.GetLastException() {
    if [[ -f /tmp/stored_exception ]] && [[ -f /tmp/stored_exception_line ]] && [[ -f /tmp/stored_exception_source ]]
    then
        cat /tmp/stored_exception
        cat /tmp/stored_exception_line
        cat /tmp/stored_exception_source
    else
        echo -e " \n${BASH_LINENO[1]}\n${BASH_SOURCE[2]#./}"
    fi

    rm -f /tmp/stored_exception /tmp/stored_exception_line /tmp/stored_exception_source
    return 0
}

你可以自由使用,分叉和贡献——它在GitHub上。

借用肖恩·梅奥的回答,你可以这样做

function check {
EXITCODE=$?
if [ "$EXITCODE" -ne "0" ]; then
    #this is the catch part
    echo "uh oh"
    exit $EXITCODE
fi
}

YOUR COMMAND HERE
check
YOUR COMMAND HERE
check
YOUR COMMAND HERE
check
YOUR COMMAND HERE
check

效果很好

我用了一个非常简单的方法:

try() {
    "$@" || (e=$?; echo "$@" > /dev/stderr; exit $e)
}

我建议在“bash -ue”模式下这样做:

set -ue
   
false && RET=$? || RET=$? 
echo "expecting 1, got ${RET}"
true && RET=$? || RET=$? 
echo "expecting 0, got ${RET}"

echo "test try...catch"
false && RET=$? || RET=$? 
if [ ${RET} -ne 0 ]; then
  echo "caught error ${RET}"
fi

echo "beware, using '||' before '&&' fails"
echo "  -> memory aid: [A]nd before [O]r in the alphabet"
false || RET=$? && RET=$? 
echo "expecting 1, got ${RET}"
true || RET=$? && RET=$? 
echo "expecting 0, got ${RET}"