在Bash中是否有TRY CATCH命令?

我正在编写一个Shell脚本,需要检查是否安装了terminal应用程序。 我想用一个TRY / CATCH命令来做这个,除非有一个更好的方法。

在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还包含一些error handling机制

 set -e 

如果一个简单的命令失败,它会立即停止你的脚本。 我认为这应该是默认行为。 由于这样的错误几乎总是意味着意想不到的事情,所以继续执行下面的命令并不是“理智的”。

还有,为什么不if...else 这是你最好的朋友。

根据我在这里find的一些答案,我自己做了一个小帮手文件来源为我的项目:

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 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 } 

我在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块embedded自己的内部!

 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样板/框架的一部分 。 它进一步扩展了尝试和捕捉与回溯和exceptionerror handling(加上一些其他不错的function)的东西的想法。

这里是负责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上 。

bash不会中止正在运行的执行,以防sth检测到错误状态(除非您设置了-e标志)。 提供try/catch编程语言是为了抑制由于这种特殊情况(因此通常被称为“exception”)的“救援”。

bash ,相反,只有有问题的命令才会以大于0的退出码退出,表示错误状态。 你当然可以检查,但是因为没有任何东西可以自动解救 ,所以一个try / catch就没有意义了。 这只是缺乏这样的背景。

但是,您可以通过使用可以在您决定的点终止的子弹来模拟救助

 ( echo "Do one thing" echo "Do another thing" if some_condition then exit 3 # <-- this is our simulated bailing out fi echo "Do yet another thing" echo "And do a last thing" ) # <-- here we arrive after the simulated bailing out, and $? will be 3 (exit code) if [ $? = 3 ] then echo "Bail out detected" fi 

而不是那个some_condition if你也可以只是尝试一个命令,并在万一失败 (退出代码大于0),保释:

 ( echo "Do one thing" echo "Do another thing" some_command || exit 3 echo "Do yet another thing" echo "And do a last thing" ) ... 

不幸的是,使用这种技术只能使用255个不同的退出代码(1..255),并且不能使用像样的exception对象。

如果你需要更多的信息来传递你的模拟exception,你可以使用subshel​​l的标准输出,但这有点复杂,也许是另一个问题;-)

使用上面提到的-e标志,你甚至可以去掉这个显式的exit语句:

 ( set -e echo "Do one thing" echo "Do another thing" some_command echo "Do yet another thing" echo "And do a last thing" ) ... 

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

所以,一种模拟try / catch块的技术是启动一个subprocess来执行-e启用的工作。 然后在主进程中检查subprocess的返回码。

Bash支持heredocstring,所以你不必编写两个单独的文件来处理这个问题。 在下面的示例中,TRY heredoc将在单独的bash实例中运行,并启用了-e ,因此如果有任何命令返回非零的退出代码,subprocess将会崩溃。 然后,回到主进程中,我们可以检查返回代码来处理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块,但它可能会为您划伤类似的痒。

你可以使用trap

try { block A } catch { block B } finally { block C }

转化为:

 ( set -Ee function _catch { block B exit 0 # optional; use if you don't want to propagate (rethrow) error to outer shell } function _finally { block C } trap _catch ERR trap _finally EXIT block A ) 

有这么多类似的解决scheme,可能工作。 下面是一个简单而实用的方法来完成try / catch,并在评论中解释。

 #!/bin/bash function a() { # do some stuff here } function b() { # do more stuff here } # this subshell is a scope of try # try ( # this flag will make to exit from current subshell on any error # inside it (all functions run inside will also break on any error) set -e a b # do more stuff here ) # and here we catch errors # catch errorCode=$? if [ $errorCode -ne 0 ]; then echo "We have an error" # We exit the all script with the same error, if you don't want to # exit it and continue, just delete this line. exit $errorCode fi 

我使用一个非常简单的东西:

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