是否有像Java try catch这样的linux bash命令?还是linux shell总是会继续运行?
try {
`executeCommandWhichCanFail`
mv output
} catch {
mv log
} finally {
rm tmp
}
是否有像Java try catch这样的linux bash命令?还是linux shell总是会继续运行?
try {
`executeCommandWhichCanFail`
mv output
} catch {
mv log
} finally {
rm tmp
}
Answers:
好吧,有点:
{ # your 'try' block
executeCommandWhichCanFail &&
mv output
} || { # your 'catch' block
mv log
}
rm tmp # finally: this will always happen
&&
之后,executeCommandWhichCanFail
否则会盲目进行。即使您先使用它set -e
(我也不知道)。
trap
,因为||
即使在特殊条件(信号)下也不能确保另一部分得到执行,这几乎是人们期望的finally
。
(...)
代替,{...}
然后不必在每行上使用&&
根据您的示例,无论脚本如何退出,您似乎都在尝试执行类似于始终删除临时文件的操作。在Bash中,请尝试使用trap
内置命令捕获EXIT
信号。
#!/bin/bash
trap 'rm tmp' EXIT
if executeCommandWhichCanFail; then
mv output
else
mv log
exit 1 #Exit with failure
fi
exit 0 #Exit with success
脚本退出时始终执行中的rm tmp
语句trap
,因此将始终尝试删除文件“ tmp”。
安装的疏水阀也可以复位;仅使用信号名称的trap调用将重置信号处理程序。
trap EXIT
有关更多详细信息,请参见bash手册页: man bash
trap 'rm tmp' EXIT SIGINT
。
EXIT
处理程序也呼吁SIGINT
和SIGTERM
if/else
或||
方法。try
catch
我使用以下语法在脚本中找到了成功:
# Try, catch, finally
(echo "try this") && (echo "and this") || echo "this is the catch statement!"
# this is the 'finally' statement
echo "finally this"
如果try语句抛出错误或以结束exit 1
,则解释器将继续执行catch语句,然后再执行finally语句。
如果两个try语句都成功(和/或以结尾exit
),则解释器将跳过catch语句,然后运行finally语句。
范例_1:
goodFunction1(){
# this function works great
echo "success1"
}
goodFunction2(){
# this function works great
echo "success2"
exit
}
(goodFunction1) && (goodFunction2) || echo "Oops, that didn't work!"
echo "Now this happens!"
输出_1
success1
success2
Now this happens!
范例_2
functionThrowsErr(){
# this function returns an error
ech "halp meh"
}
goodFunction2(){
# this function works great
echo "success2"
exit
}
(functionThrowsErr) && (goodFunction2) || echo "Oops, that didn't work!"
echo "Now this happens!"
输出_2
main.sh: line 3: ech: command not found
Oops, that didn't work!
Now this happens!
范例_3
functionThrowsErr(){
# this function returns an error
echo "halp meh"
exit 1
}
goodFunction2(){
# this function works great
echo "success2"
}
(functionThrowsErr) && (goodFunction2) || echo "Oops, that didn't work!"
echo "Now this happens!"
输出_3
halp meh
Oops, that didn't work!
Now this happens!
请注意,功能的顺序将影响输出。如果您需要分别尝试和捕获这两个语句,请使用两个try catch语句。
(functionThrowsErr) || echo "Oops, functionThrowsErr didn't work!"
(goodFunction2) || echo "Oops, good function is bad"
echo "Now this happens!"
输出量
halp meh
Oops, functionThrowsErr didn't work!
success2
Now this happens!
另一种方法是:
set -e; # stop on errors
mkdir -p "$HOME/tmp/whatevs"
exit_code=0
(
set +e;
(
set -e;
echo 'foo'
echo 'bar'
echo 'biz'
)
exit_code="$?"
)
rm -rf "$HOME/tmp/whatevs"
if [[ "exit_code" != '0' ]]; then
echo 'failed';
fi
尽管以上内容并未真正带来任何好处:
set -e; # stop on errors
mkdir -p "$HOME/tmp/whatevs"
exit_code=0
(
set -e;
echo 'foo'
echo 'bar'
echo 'biz'
exit 44;
exit 43;
) || {
exit_code="$?" # exit code of last command which is 44
}
rm -rf "$HOME/tmp/whatevs"
if [[ "exit_code" != '0' ]]; then
echo 'failed';
fi
当我添加其他选项或以其他方式更改它们时,我常常会导致bash脚本变得很大。当bash脚本包含许多功能时,使用'trap EXIT'可能会变得很简单。
例如,考虑一个脚本被调用为
dotask TASK [ARG ...]
其中每个TASK
子步骤都可以包含子步骤,因此需要在它们之间进行清理。
在这种情况下,使用子外壳来产生作用域出口陷阱很有帮助,例如
function subTask (
local tempFile=$(mktemp)
trap "rm '${tempFile}'" exit
...
)
但是,使用子外壳可能很棘手,因为它们无法设置父外壳的全局变量。
另外,编写单个出口陷阱通常很不方便。例如,清理步骤可能取决于函数在遇到错误之前走了多远。能够进行RAII样式清理声明将是一件很不错的事情:
function subTask (
...
onExit 'rm tmp.1'
...
onExit 'rm tmp.2'
...
)
使用类似的东西似乎很明显
handlers=""
function onExit { handlers+="$1;"; trap "$handlers" exit; }
更新陷阱。但这对于嵌套子shell失败,因为这会导致父shell的处理程序过早执行。客户端代码将必须handlers
在子Shell的开头显式重置变量。
[针对同一信号的多个bash陷阱]中讨论的解决方案,通过使用来自的输出来修补陷阱,trap -p EXIT
同样会失败:即使子外壳程序不继承EXIT
陷阱,trap -p exit
也会显示父外壳程序的处理程序,因此,同样需要手动重置。