bash 抓捕异常_shell - Bash中是否有TRY CATCH命令

刘狐若
2023-12-01

shell - Bash中是否有TRY CATCH命令

我正在编写一个shell脚本,需要检查是否已安装终端应用程序。 我想使用TRY / CATCH命令来执行此操作,除非有更简洁的方法。

10个解决方案

351 votes

Bash中有TRY CATCH命令吗?

没有。

Bash并没有像许多编程语言中那样多的奢侈品。

bash中没有if...else; 但是,使用command2或command1可以实现类似的行为。

使用if...else:

如果if...else失败,则command2运行如下

command1 || command2

同样,如果command1成功,将使用if...else,command2

最接近if...else如下

{ # try

command1 &&

#save your output

} || { # catch

# save log for exception

}

bash也包含一些错误处理机制

set -e

如果简单命令失败,它将立即停止您的脚本。 我认为这应该是默认行为。 由于这些错误几乎总是意味着意外的事情,因此继续执行以下命令并不是“理智”。

而且为什么不是if...else.这是你最好的朋友。

Jayesh Bhoi answered 2019-03-05T20:59:35Z

73 votes

基于我在这里找到的一些答案,我为自己的项目提供了一个小帮手文件:

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

}

Mathias Henze answered 2019-03-05T21:00:12Z

53 votes

我已经开发了一个几乎完美的尝试& 在bash中捕获实现,允许您编写如下代码:

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& amp; 通过回溯和异常(以及其他一些不错的功能)来处理错误处理等事情。

这是代码,它只对try& 抓住:

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上。

niieani answered 2019-03-05T21:00:39Z

11 votes

-e在sth检测到错误状态的情况下不会中止正在运行的执行(除非您设置exit标志)。 提供try/catch的编程语言是为了抑制由于这种特殊情况而导致的“纾困”(因此通常称为“异常”)。

相反,在-e中,只有相关命令将以退出代码大于0退出,表示错误状态。 当然可以检查,但由于没有自动拯救任何东西,尝试/捕获没有意义。 它只是缺乏这种背景。

但是,你可以通过使用子shell来模拟拯救,这些子shell可以在你决定的点终止:

(

echo "Do one thing"

echo "Do another thing"

if some_condition

then

exit 3 #

fi

echo "Do yet another thing"

echo "And do a last thing"

) #

if [ $? = 3 ]

then

echo "Bail out detected"

fi

你也可以尝试一个命令而不是那个-e,如果它失败(退出代码大于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),并且不能使用任何体面的异常对象。

如果你需要更多信息传递模拟异常,你可以使用子shell的stdout,但这有点复杂,也许是另一个问题;-)

使用上面提到的-e标志到shell,您甚至可以删除明确的exit语句:

(

set -e

echo "Do one thing"

echo "Do another thing"

some_command

echo "Do yet another thing"

echo "And do a last thing"

)

...

Alfe answered 2019-03-05T21:01:45Z

11 votes

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

因此,模拟try / catch块的一种技术是启动子进程以启用-e。 然后在主进程中,检查子进程的返回码。

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

#!/bin/bash

set +e

bash -e <

echo hello

cd /does/not/exist

echo world

TRY

if [ $? -ne 0 ]; then

echo caught exception

fi

它不是一个适当的语言支持的try / catch块,但它可能会为你划伤类似的痒。

Dan Fabulich answered 2019-03-05T21:02:35Z

9 votes

你可以使用try { block A } catch { block B } finally { block C }:

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

)

Mark K Cowan answered 2019-03-05T21:03:14Z

7 votes

有这么多类似的解决方案可能有效。 下面是一个简单而有效的方法来完成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

Kostanos answered 2019-03-05T21:03:40Z

4 votes

你有陷阱[http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html]这是不一样的,但你可以用于此目的的其他技术

Eran Ben-Natan answered 2019-03-05T21:04:07Z

1 votes

你可以做:

#!/bin/bash

if ; then # TRY

else # CATCH

echo 'Exception'

fi

Davidson Lima answered 2019-03-05T21:04:29Z

0 votes

我使用的一件非常简单的事情:

try() {

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

}

syberghost answered 2019-03-05T21:04:55Z

 类似资料: