#!/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
}
11
我在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__!"
}
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
}
(
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
#!/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块,但它可能会为你划伤类似的痒 .
74
你可以使用 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
)
#!/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
10 回答
没有 .
Bash并没有像许多编程语言中那样多的奢侈品 .
bash中没有
try/catch
;但是,使用&&
或||
可以实现类似的行为 .使用
||
:如果
command1
失败,则command2
运行如下同样,如果
command1
成功,则使用&&
,command2
将运行try/catch
的最接近的近似如下bash也包含一些错误处理机制
如果简单命令失败,它将立即停止您的脚本 . 我认为这应该是默认行为 . 由于这些错误几乎总是意味着意外的事情,因此继续执行以下命令并不是“理智” .
而且为什么不
if...else
. 这是你最好的朋友 .基于我在这里找到的一些答案,我为自己的项目提供了一个小帮手文件:
trycatch.sh
这是一个如何使用的示例:
我在bash中开发了一个几乎完美无缺的try&catch实现,允许你编写如下代码:
你甚至可以将try-catch块嵌入其中!
代码是我bash boilerplate/framework的一部分 . 它进一步扩展了try&catch的概念,例如带有回溯和异常的错误处理(以及一些其他不错的功能) .
这是负责try&catch的代码:
随意使用,分叉和贡献 - 它在GitHub .
bash
在中断检测到错误状态时不会中止正在运行的执行(除非您设置了-e
标志) . 提供try/catch
的编程语言是为了禁止"bailing out",因为这种特殊情况(因此通常称为"exception") .而在
bash
中,只有相关命令将以退出代码大于0退出,表示错误状态 . 当然可以检查,但由于没有自动拯救任何东西,尝试/捕获没有意义 . 它只是缺乏这种背景 .但是,你可以通过使用子shell来模拟拯救,这些子shell可以在你决定的点终止:
你可以尝试一个命令而不是
some_condition
而不是some_condition
,如果它失败(退出代码大于0),纾困:不幸的是,使用这种技术,你只能使用255个不同的退出代码(1..255),并且不能使用任何体面的异常对象 .
如果你需要更多信息传递模拟异常,你可以使用子shell的stdout,但这有点复杂,也许是另一个问题;-)
使用上面提到的
-e
标志到shell,您甚至可以删除明确的exit
语句:正如大家所说,bash没有适当的语言支持的try / catch语法 . 如果任何命令具有非零退出代码,则可以使用
-e
参数启动bash或使用脚本内的set -e
来中止整个bash进程 . (您也可以set +e
暂时允许失败的命令 . )因此,模拟try / catch块的一种技术是启动一个子流程来启用
-e
. 然后在主进程中,检查子进程的返回码 .Bash支持heredoc字符串,因此您不必编写两个单独的文件来处理它 . 在下面的示例中,TRY heredoc将在单独的bash实例中运行,并启用
-e
,因此如果任何命令返回非零退出代码,则子进程将崩溃 . 然后,回到主进程,我们可以检查返回代码来处理catch块 .它不是一个适当的语言支持的try / catch块,但它可能会为你划伤类似的痒 .
你可以使用
trap
:try { block A } catch { block B } finally { block C }
翻译为:
有这么多类似的解决方案可能有效 . 下面是一个简单而有效的方法来完成try / catch,并在注释中进行了解释 .
你有陷阱http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html这是不一样的,但你可以用于此目的的其他技术
你可以做:
我使用的一件非常简单的事情: