保存退出代码以备后用

mat*_*ots 17 shell bash exit-status

所以我有一个小脚本来运行一些测试。

javac *.java && java -ea Test
rm -f *.class
Run Code Online (Sandbox Code Playgroud)

现在的问题是,当我运行脚本时./test,即使测试因为rm -f *.class成功而失败,它也会返回成功退出代码。

我能想到的让它做我想做的事情的唯一方法对我来说很丑陋:

javac *.java && java -ea Test
test_exit_code=$?
rm -f *.class
if [ "$test_exit_code" != 0 ] ; then false; fi
Run Code Online (Sandbox Code Playgroud)

但这似乎是一个常见问题——执行任务,清理,然后返回原始任务的退出代码。

这样做的最惯用的方法是什么(在 bash 或一般的 shell 中)?

mur*_*uru 23

我会去:

javac *.java && java -ea Test
test_exit_code=$?
rm -f *.class
exit "$test_exit_code"
Run Code Online (Sandbox Code Playgroud)

为什么在exit可用时跳来跳去?


你可以使用一个trap

trap 'last_error_code=$?' ERR
Run Code Online (Sandbox Code Playgroud)

例如:

$ trap 'last_error_code=$?' ERR
$ false
$ echo $?
1
$ echo $last_error_code $?
1 0
Run Code Online (Sandbox Code Playgroud)


Dav*_*d Z 11

据我所知,bash 最接近try...finally类似 C 的编程语言的块(如果它可用trap,这就是您可能想要的)是构造,其工作方式如下:

trap "rm -f *.class" EXIT
javac *.java && java -ea Test
Run Code Online (Sandbox Code Playgroud)

这将在您的脚本退出时执行“rm -f *.class”。如果你有更复杂的事情要做,你可以把它放在一个函数中:

cleanup() {
    ...
}
trap cleanup EXIT
javac *.java && java -ea Test
Run Code Online (Sandbox Code Playgroud)

如果你愿意,你可以把它变成一个相当通用的习语,它的工作原理大致类似于try...catch...finallyC 中的块。 像这样:

(
  trap "catch_block; exit" ERR
  trap finally_block EXIT
  # contents of try goes here
)
Run Code Online (Sandbox Code Playgroud)

请注意,括号界定了一个子shell;使用这种结构,如果命令失败,则只有子外壳退出,而不是整个脚本。请记住,子外壳在计算上有些昂贵,因此不要使用太多(数百个)。根据您的脚本,您可以使用 shell 函数和 更有效地实现相同的效果trap ... RETURN,但这取决于您的调查。


mik*_*erv 5

您可以将exitrm命令包装成一个简单的命令,eval例如:

java ... && java ...
eval "rm -f *.class; exit $?"
Run Code Online (Sandbox Code Playgroud)

$?传递给方式时的值exit是它在eval运行之前立即分配的任何值。