`{{(出口1); 1号出口;}; }`是什么意思?


28

我引用了config.status产生的下一个代码段configure

if test ! -f "$as_myself"; then
{ { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
{ (exit 1); exit 1; }; }
fi

在代码段中,该怎么{ (exit 1); exit 1; };做?仅exit在子外壳中执行操作的目的是什么?

Answers:


33

执行(exit 1);是触发ERR陷阱的最简单方法。如果有效,它还将触发立即退出set -e。(触发错误条件需要命令失败;exit子shell中的失败值会导致子shell失败。)

exit 1; 不会做任何事情。

因此{(exit 1); exit 1;}可以用来首先生成ERR陷阱,该陷阱可能会为调试目的做一些有用的事情,然后使用错误指示终止脚本。

但这不是autoconf文件中正在发生的事情。autoconf脚本依靠EXIT陷阱来清除运行期间创建的临时文件。大多数shell(包括shell)bashexit在调用EXIT陷阱之前根据命令中提供的值来设置状态。这可以使EXIT陷阱能够检测到它是从错误中调用还是从正常终止中被调用,还可以确保陷阱操作结束时正确设置了退出状态。

但是,显然有些外壳无法配合使用。这是autoconf手册的引文:

有些shell脚本(例如由生成的shell脚本)autoconf在退出之前使用陷阱进行清理。如果最后一个shell命令以非零状态退出,则陷阱也以非零状态退出,以便调用程序可以知道发生了错误。

不幸的是,在某些Shell中,例如Solaris /bin/sh,出口陷阱会忽略出口命令的参数。在这些shell中,陷阱无法确定是由普通出口还是由出口1调用的。与其直接调用exit,不如使用AC_MSG_ERROR具有解决此问题的方法的宏。

解决方法是确保$?有退出状态之前exit执行命令,这样当它必定会对这个值EXIT执行陷阱。实际上,正是AC_MSG_ERROR宏插入了好奇的代码,并带有多余的花括号。


为什么不执行false而不是执行(exit 1)
Ruslan 2014年

3
@Ruslan:两个问题。(1)最重要的是:false不允许您设置状态代码,也不能保证它返回什么非零状态。(2)false通常不是内置的,因此需要一个子进程;相比之下,大多数贝壳可以避免产生一个要处理的孩子(exit 1)
rici 2014年

8

据我所知,这没有任何目的,启动子shell然后立即退出无法直接实现。

这样的事情很可能是自动生成代码的副作用-在某些情况下,子外壳中可能还会执行其他exit 1有意义的命令。最终,很有可能会通过某种方式简化生成代码,方法是允许它插入某些情况下不具有任何功能的语句,而每次生成“干净代码”则更加复杂。要么或者生成上面的代码写得很差:)

自由使用{...}是这的另一个示例,其中大多数是多余的,但是编写代码在每种情况下都插入它们(可能在某些情况下要重定向块的输出/输入)要容易得多,而不是区分它们。不需要它们的地方,并忽略它们。


它确实有目的。参见@rici的答案。
老专业

1

(exit 1)是获得特定退出代码的简单方法,可能是最简单的方法(当然,在1的特殊情况下,还有更简单的方法)。但这不是这种情况的原因,因为未检查退出代码。

放入exit子shell 的目的可能是不退出脚本(尽管使用exit来生成某些退出代码)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.