Subject: Re: make -j and failure modes
To: James Chacon <>
From: Robert Elz <kre@munnari.OZ.AU>
List: tech-userlevel
Date: 12/11/2003 01:26:35
    Date:        Wed, 10 Dec 2003 10:45:04 -0600
    From:        James Chacon <>
    Message-ID:  <>

  | Actually I was saying the parent shell would exit because the sub-shell
  | returned non-zero for *any* reason. At that point the sub shell is just
  | a process returning an exit code.

If you want a process returning an exit code, use "sh -ec 'commands'"
and I believe it will do what you want.   A command sequence written
in () is not "just a process returning an exit code", it is a command
group, that happens to run in a sub-shell.   Groups enclosed in { }
should work the same way (wrt -e) without the sub-shell., though I
haven't tested that one.

  | Both of these are excluded from -e tests anyways. It lists exceptions for
  | AND and OR.

Yes, it also explicitly says just "simple commands".
Then it goes on and excludes even some of those, so it isn't
even all simple commands (but certainly nothing which isn't simple
counts, and a compound command certainly is not simple).

  | Why the subshell returned 1 is up to the subshell (it could very well have
  | turned off -e, that's it's business). The fact it returned a non-zero exit
  | code is what's important to the parent shell.

But that isn't what the spec says, and it isn't what is usually useful.

  | For what reason? The command in question exited non-zero for some reason. 
  | Whatever the reason was it's concern. The parent process though is set to
  | exit (via -e) for anything that returns non-zero and this would meet that
  | criteria since it isn't in the exception list for -e.

Then how would you handle a Makefile that happened to contain

	(cd dir && test -f file && cat file)

If file doesn't exist, that will exit 1, as the last command
executed is te test, which failed (same if dir doesn't exist).

But that isn't what is wanted - the intent there is simply to cat
the file, if it exists, and do nothing if it doesn't.

This is why the && exception exists in the rules - nothing else makes
sense.   How can doing it in a sub-shell (needed so the cd doesn't
change the parent shell) possibly be intended to change the result?
That makes no sense.

  | No. It was the subshell exiting non-zero that's being ignored.
  | Run a make rule of
  | all:
  |         (false)
  |         echo foo
  | via make -j (which feeds that into sh -ev) and echo foo will be printed.
  | Not exactly expected behavior from make at all.

No.   But that is make's problem.
Not the shells - make is using sh incorrectly.

Make -j is simply broken (in yet another way) - just avoid it.


ps: "man sh" is also broken in its description of -e - what it
describes is nothing like the shell actually implements.   The implementation,
as much as I have tested anyway seems correct, the man page is incorrect.
(The ksh man page is better).