29

I quoted the next code snippet from config.status generated by 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

In the code snippet, what does { (exit 1); exit 1; }; do? What's the purpose of only doing exit in a subshell?

3 Answers 3

35

Executing (exit 1); is the simplest way of triggering an ERR trap. It will also trigger immediate exit if set -e is in effect. (Triggering the error condition requires a command to fail; exit with a failure value in a subshell causes the subshell to fail.)

exit 1; will do neither of those things.

So {(exit 1); exit 1;} can be used to first produce the ERR trap, which might do something useful for debugging purposes, and then terminate the script with an error indication.

But that's not what is going on in autoconf files. autoconf scripts rely on the EXIT trap in order to clean up temporary files created during the run. Most shells, including bash will set the status from the value provided in the exit command before calling the EXIT trap. That could allow the EXIT trap to detect whether it was invoked from an error or from normal termination, and it also allows it to ensure that the exit status is correctly set at the end of the trap operation.

However, apparently some shells do not co-operate. Here's a quote from the autoconf manual:

Some shell scripts, such as those generated by autoconf, use a trap to clean up before exiting. If the last shell command exited with nonzero status, the trap also exits with nonzero status so that the invoker can tell that an error occurred.

Unfortunately, in some shells, such as Solaris /bin/sh, an exit trap ignores the exit command's argument. In these shells, a trap cannot determine whether it was invoked by plain exit or by exit 1. Instead of calling exit directly, use the AC_MSG_ERROR macro that has a workaround for this problem.

The workaround is to make sure that $? has the exit status before the exit command is executed, so that it will definitely have that value when the EXIT trap is executed. And, indeed, it is the AC_MSG_ERROR macro which inserts that curious code, complete with redundant braces.

2
  • Why not just execute false instead of (exit 1)?
    – Ruslan
    Commented Jun 16, 2014 at 9:13
  • 3
    @Ruslan: Two problems. (1) Most important: false doesn't let you set the status code and there is no guarantee as to what non-zero status it returns. (2) false is not usually a builtin, so it requires a child process; in contrast, most shells can avoid spawning a child to handle (exit 1).
    – rici
    Commented Jun 16, 2014 at 15:05
8

There is no purpose for this as far as I can see, there is nothing that can be achieved directly by starting a subshell and then immediately exiting.

Things like this are most likely a side effect of automatically generating code - in some cases there may be other commands executed in the subshell where having the exit 1 makes sense. Ultimately there is a good chance that the generation code is somehow simplified by allowing it to insert some statements that don't have any function in some cases rather and generating 'clean code' every single time is more complex. Either that or the code which generated the above is just poorly written :)

The liberal use of {...} is another example of this, most of them are redundant, but it is easier to write code that inserts them in every case (maybe in some you want to redirect the output/input of the block) rather than to distinguish the ones where they are not needed and omit them.

1
  • It does have a purpose. See @rici's answer.
    – Old Pro
    Commented Jun 16, 2014 at 5:09
2

(exit 1) is a simple, probably the most simple way to get a certain exit code (in the special case of 1 there are easier ways, of course). But that is not the reason in this case as the exit code is not examined.

The purpose of putting exit in a subshell may be to not exit the script (though using exit for the generation of a certain exit code).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .