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


当前回答

我建议在“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}"

其他回答

我使用的方法是这样的:

YOUR COMMAND HERE
EXITCODE=$?
if [ "$EXITCODE" -ne "0" ]; then
    #this is the catch part
    echo "uh oh"
    exit $EXITCODE
fi

这只是检查命令的退出码,并将其与零进行比较 (表示命令运行成功)

正如大家所说,bash没有适当的语言支持的try/catch语法。您可以使用-e参数启动bash,或者在脚本中使用set -e来中止整个bash进程,如果任何命令有非零退出码的话。(你也可以设置+e来临时允许失败的命令。)

因此,模拟try/catch块的一种技术是在启用-e的情况下启动子进程来完成工作。然后在主进程中,检查子进程的返回码。

Bash支持heredoc字符串,因此不需要编写两个单独的文件来处理这个问题。在下面的示例中,TRY heredoc将在单独的bash实例中运行,并启用了-e,因此如果任何命令返回非零退出码,子进程将崩溃。然后,回到主进程,我们可以检查返回代码以处理一个catch块。

#!/bin/bash

set +e
bash -e <<TRY
  echo hello
  cd /does/not/exist
  echo world
TRY
if [ $? -ne 0 ]; then
  echo caught exception
fi

它不是一个适当的语言支持的try/catch块,但它可能会为您带来类似的体验。

你可以:

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

根据我在这里找到的一些答案,我为自己的项目制作了一个小的帮助文件:

trycatch.sh

#!/bin/bash

function try()
{
    [[ $- = *e* ]]; SAVED_OPT_E=$?
    set +e
}

function throw()
{
    exit $1
}

function catch()
{
    export ex_code=$?
    (( $SAVED_OPT_E )) && set +e
    return $ex_code
}

function throwErrors()
{
    set -e
}

function ignoreErrors()
{
    set +e
}

下面是它在使用中的示例:

#!/bin/bash
export AnException=100
export AnotherException=101

# start with a try
try
(   # open a subshell !!!
    echo "do something"
    [ someErrorCondition ] && throw $AnException

    echo "do something more"
    executeCommandThatMightFail || throw $AnotherException

    throwErrors # automaticatly end the try block, if command-result is non-null
    echo "now on to something completely different"
    executeCommandThatMightFail

    echo "it's a wonder we came so far"
    executeCommandThatFailsForSure || true # ignore a single failing command

    ignoreErrors # ignore failures of commands until further notice
    executeCommand1ThatFailsForSure
    local result = $(executeCommand2ThatFailsForSure)
    [ result != "expected error" ] && throw $AnException # ok, if it's not an expected error, we want to bail out!
    executeCommand3ThatFailsForSure

    # make sure to clear $ex_code, otherwise catch * will run
    # echo "finished" does the trick for this example
    echo "finished"
)
# directly after closing the subshell you need to connect a group to the catch using ||
catch || {
    # now you can handle
    case $ex_code in
        $AnException)
            echo "AnException was thrown"
        ;;
        $AnotherException)
            echo "AnotherException was thrown"
        ;;
        *)
            echo "An unexpected exception was thrown"
            throw $ex_code # you can rethrow the "exception" causing the script to exit if not caught
        ;;
    esac
}

假设终端应用名为'app'(你希望它在你的$PATH中):

if [[ ! `which app` ]]; then
    # run code if app not installed
else
    # run code if app is installed
fi