所以我有一个用于运行一些测试的小脚本。
javac *.java && java -ea Test
rm -f *.class
现在的问题是,当我运行脚本时./test
,即使测试失败,它也会返回成功退出代码,因为rm -f *.class
成功了。
我能想到的让它做我想做的事情的唯一方法对我来说感觉很丑陋:
javac *.java && java -ea Test
test_exit_code=$?
rm -f *.class
if [ "$test_exit_code" != 0 ] ; then false; fi
但这似乎是一个常见问题——执行任务,清理,然后返回原始任务的退出代码。
最惯用的方法是什么(在 bash 或一般的 shell 中)?
答案1
我会选择:
javac *.java && java -ea Test
test_exit_code=$?
rm -f *.class
exit "$test_exit_code"
exit
为什么要在可用时跳来跳去?
你可以使用trap
:
trap 'last_error_code=$?' ERR
例如:
$ trap 'last_error_code=$?' ERR
$ false
$ echo $?
1
$ echo $last_error_code $?
1 0
答案2
据我所知,bashtry...finally
与类似 C 的编程语言(如果有的话,您可能会想要的)最接近的东西是构造trap
,其工作原理如下:
trap "rm -f *.class" EXIT
javac *.java && java -ea Test
当脚本退出时,这将执行“rm -f *.class”。如果你有更复杂的事情要做,你可以把它放在一个函数中:
cleanup() {
...
}
trap cleanup EXIT
javac *.java && java -ea Test
如果您愿意,您可以将其变成一个相当通用的习惯用法,其工作方式大致类似于try...catch...finally
C 中的块。如下所示:
(
trap "catch_block; exit" ERR
trap finally_block EXIT
# contents of try goes here
)
请注意,括号分隔子 shell;通过这种构造,如果命令失败,则仅退出子 shell,而不是整个脚本。请记住,子 shell 在计算上有些昂贵,因此不要使用太多(数百个)子 shell。根据您的脚本,您可能能够使用 shell 函数 和 更有效地实现相同的效果trap ... RETURN
,但这取决于您的研究。
答案3
您可以将exit
和rm
命令包装成一个简单命令,例如eval
:
java ... && java ...
eval "rm -f *.class; exit $?"
way$?
传递给的值是在运行exit
之前立即分配的值。eval
答案4
为了让你的方法稍微不那么麻烦,我会exit
在子 shell 中使用:
javac *.java && java -ea Test
test_exit_code=$?
rm -f *.class
(exit $test_exit_code)