保存退出代码供以后使用

保存退出代码供以后使用

所以我有一个用于运行一些测试的小脚本。

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...finallyC 中的块。如下所示:

(
  trap "catch_block; exit" ERR
  trap finally_block EXIT
  # contents of try goes here
)

请注意,括号分隔子 shell;通过这种构造,如果命令失败,则仅退出子 shell,而不是整个脚本。请记住,子 shell 在计算上有些昂贵,因此不要使用太多(数百个)子 shell。根据您的脚本,您可能能够使用 shell 函数 和 更有效地实现相同的效果trap ... RETURN,但这取决于您的研究。

答案3

您可以将exitrm命令包装成一个简单命令,例如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)

相关内容