我正在写一个shell脚本,需要检查终端应用程序是否已安装。我想使用TRY/CATCH命令来做到这一点,除非有更整洁的方法。
当前回答
借用肖恩·梅奥的回答,你可以这样做
function check {
EXITCODE=$?
if [ "$EXITCODE" -ne "0" ]; then
#this is the catch part
echo "uh oh"
exit $EXITCODE
fi
}
YOUR COMMAND HERE
check
YOUR COMMAND HERE
check
YOUR COMMAND HERE
check
YOUR COMMAND HERE
check
效果很好
其他回答
Bash不会在检测到错误状态时中止正在运行的执行(除非您设置了-e标志)。提供try/catch的编程语言这样做是为了抑制由于这种特殊情况而产生的“保释”(因此通常称为“异常”)。
相反,在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),而且不能使用像样的异常对象。
如果你需要更多的信息来传递模拟异常,你可以使用subshell的stdout,但这有点复杂,可能是另一个问题;-)
使用上面提到的-e标志,你甚至可以剥离显式的退出语句:
(
set -e
echo "Do one thing"
echo "Do another thing"
some_command
echo "Do yet another thing"
echo "And do a last thing"
)
...
根据我在这里找到的一些答案,我为自己的项目制作了一个小的帮助文件:
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
}
有很多类似的解决方案可能会起作用。下面是一个简单有效的方法来完成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
你可以:
#!/bin/bash
if <command> ; then # TRY
<do-whatever-you-want>
else # CATCH
echo 'Exception'
<do-whatever-you-want>
fi
你可以使用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
)