Bash 中是否有 TRY CATCH 命令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22009364/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a TRY CATCH command in Bash
提问by Lee Probert
I'm writing a shell script and need to check that a terminal app has been installed. I want to use a TRY/CATCH command to do this unless there is a neater way.
我正在编写一个 shell 脚本,需要检查是否已安装终端应用程序。除非有更简洁的方法,否则我想使用 TRY/CATCH 命令来执行此操作。
回答by Jayesh Bhoi
Is there a TRY CATCH command in Bash?
Bash 中是否有 TRY CATCH 命令?
No.
不。
Bash doesn't have as many luxuries as one can find in many programming languages.
Bash 没有像许多编程语言中那样多的优点。
There is no try/catch
in bash; however, one can achieve similar behavior using &&
or ||
.
try/catch
bash 中没有;但是,可以使用&&
或实现类似的行为||
。
Using ||
:
使用||
:
if command1
fails then command2
runs as follows
如果command1
失败则command2
运行如下
command1 || command2
Similarly, using &&
, command2
will run if command1
is successful
同样,使用&&
,command2
将在command1
成功时运行
The closest approximation of try/catch
is as follows
最接近的近似try/catch
如下
{ # try
command1 &&
#save your output
} || { # catch
# save log for exception
}
Also bash contains some error handling mechanisms, as well
bash 还包含一些错误处理机制,以及
set -e
it stops your script if any simple command fails.
如果任何简单命令失败,它会停止您的脚本。
And also why not if...else
. It is your best friend.
还有为什么不呢if...else
。它是你最好的朋友。
回答by Mathias Henze
Based on some answers I found here, I made myself a small helper file to source for my projects:
根据我在这里找到的一些答案,我为自己制作了一个小帮助文件来为我的项目提供资源:
trycatch.sh
尝试捕获.sh
#!/bin/bash
function try()
{
[[ $- = *e* ]]; SAVED_OPT_E=$?
set +e
}
function throw()
{
exit
}
function catch()
{
export ex_code=$?
(( $SAVED_OPT_E )) && set +e
return $ex_code
}
function throwErrors()
{
set -e
}
function ignoreErrors()
{
set +e
}
here is an example how it looks like in use:
这是一个示例,它在使用中的样子:
#!/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
}
回答by niieani
I've developed an almost flawless try & catch implementation in bash, that allows you to write code like:
我在 bash 中开发了一个几乎完美的 try & catch 实现,它允许您编写如下代码:
try
echo 'Hello'
false
echo 'This will not be displayed'
catch
echo "Error in $__EXCEPTION_SOURCE__ at line: $__EXCEPTION_LINE__!"
You can even nest the try-catch blocks inside themselves!
您甚至可以将 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__!"
}
The code is a part of my bash boilerplate/framework. It further extends the idea of try & catch with things like error handling with backtrace and exceptions (plus some other nice features).
代码是我的bash 样板/框架的一部分。它进一步扩展了 try & catch 的想法,例如使用回溯和异常处理错误(以及其他一些不错的功能)。
Here's the code that's responsible just for 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 "" > /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=
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
}
Feel free to use, fork and contribute - it's on GitHub.
随意使用、分叉和贡献——它在GitHub 上。
回答by Mark K Cowan
You can use trap
:
您可以使用trap
:
try { block A } catch { block B } finally { block C }
try { block A } catch { block B } finally { block C }
translates to:
翻译成:
(
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
)
回答by Kostanos
There are so many similar solutions which probably work. Below is a simple and working way to accomplish try/catch, with explanation in the comments.
有很多类似的解决方案可能有效。下面是一种完成 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
回答by Alfe
bash
does not abort the running execution in case something detects an error state (unless you set the -e
flag). Programming languages which offer try/catch
do this in order to inhibita "bailing out" because of this special situation (hence typically called "exception").
bash
如果检测到错误状态,则不会中止正在运行的执行(除非您设置了-e
标志)。由于这种特殊情况(因此通常称为“异常”),提供try/catch
此功能的编程语言是为了抑制“救助”。
In the bash
, instead, only the command in question will exit with an exit code greater than 0, indicating that error state. You can check for that of course, but since there is no automatic bailing outof anything, a try/catchdoes not make sense. It is just lacking that context.
在bash
, 相反,只有有问题的命令会以大于 0 的退出代码退出,表明错误状态。你当然可以检查一下,但由于没有自动退出任何东西,try/catch没有意义。它只是缺乏这种背景。
You can, however, simulate a bailing outby using sub shells which can terminate at a point you decide:
但是,您可以使用可以在您决定的点终止的子外壳来模拟救助:
(
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
Instead of that some_condition
with an if
you also can just try a command, and in case it fails(has an exit code greater than 0), bail out:
除了some_condition
使用 anif
你还可以尝试一个命令,如果它失败(退出代码大于 0),请退出:
(
echo "Do one thing"
echo "Do another thing"
some_command || exit 3
echo "Do yet another thing"
echo "And do a last thing"
)
...
Unfortunately, using this technique you are restricted to 255 different exit codes (1..255) and no decent exception objects can be used.
不幸的是,使用这种技术,您只能使用 255 个不同的退出代码 (1..255),并且无法使用合适的异常对象。
If you need more information to pass along with your simulated exception, you can use the stdout of the subshells, but that is a bit complicated and maybe another question ;-)
如果您需要更多信息与模拟异常一起传递,您可以使用子shell的标准输出,但这有点复杂,也许是另一个问题;-)
Using the above mentioned -e
flag to the shell you can even strip that explicit exit
statement:
-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"
)
...
回答by Dan Fabulich
As everybody says, bash doesn't have a proper language-supported try/catch syntax. You can launch bash with the -e
argument or use set -e
inside the script to abort the entire bash process if any command has a non-zero exit code. (You can also set +e
to temporarily allow failing commands.)
正如大家所说,bash 没有适当的语言支持的 try/catch 语法。如果任何命令具有非零退出代码,您可以-e
使用参数启动 bash或set -e
在脚本中使用以中止整个 bash 进程。(您也set +e
可以暂时允许失败的命令。)
So, one technique to simulate a try/catch block is to launch a sub-process to do the work with -e
enabled. Then in the main process, check the return code of the sub-process.
因此,模拟 try/catch 块的一种技术是启动一个子进程来执行-e
启用的工作。然后在主进程中,检查子进程的返回码。
Bash supports heredoc strings, so you don't have to write two separate files to handle this. In the below example, the TRY heredoc will run in a separate bash instance, with -e
enabled, so the sub-process will crash if any command returns a non-zero exit code. Then, back in the main process, we can check the return code to handle a catch block.
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
It's not a proper language-supported try/catch block, but it may scratch a similar itch for you.
它不是一个适当的语言支持的 try/catch 块,但它可能会为您带来类似的痒。
回答by Davidson Lima
You can do:
你可以做:
#!/bin/bash
if <command> ; then # TRY
<do-whatever-you-want>
else # CATCH
echo 'Exception'
<do-whatever-you-want>
fi
回答by Eran Ben-Natan
And you have traps http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.htmlwhich is not the same, but other technique you can use for this purpose
你有陷阱http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html这是不一样的,但是你可以使用其他技术来达到这个目的
回答by syberghost
A very simple thing I use:
我使用的一个非常简单的东西:
try() {
"$@" || (e=$?; echo "$@" > /dev/stderr; exit $e)
}