Subject: Re: make -j and failure modes
To: James Chacon <jmc@NetBSD.org>
From: Robert Elz <kre@munnari.OZ.AU>
Date: 12/11/2003 17:44:53
Since almost everyone seems not to be agreeing on what the end
result should be, I'm not going to comment on most of today's
mail on this issue, just a few random points in this message,
and some of Greywolf's in another...
| This is where the syntax is non-exact. If it only applies to simple
| commands, why bother to list exceptions for things that aren't even
| simple commands to begin with (ala the IF/WHILE etc tests).
No - the exceptions aren't to the if/while (etc) - they are to the simple
commands that are run as a part of an if/while test - there is no need to
exclude if/while themselves, as they're compound commands. Read the
if false; true
should "echo fine" regardless of whether -e is set or not, as that
"false" is part of the if test - even though it is also a simple
On the other hand
(false; echo foo); echo bar
echos foo & bar without -e, and only bar with -e - with -e, the "false" causes
the shell running the sub-shell to exit, so "echo foo" is never encountered.
but the compound is not a simple command, so the parent shell should not
I said in some earlier message:
| one assumes that if the () > are added, that's done for a reason.
and mouse@Rodents.Montreal.QC.CA replied:
| Yes, but not necessarily for _that_ reason. I've actually been annoyed by
| this: I've had to add () so that something (usually I/O redirection) can
| affect a number of commands, but have had the "push it into a subshell"
| semantics () produces get in the way.
Absolutely - but that's part of the point here I think. Trivial
mechanisms (like -e) just get in the way once you need to start being
more "creative" with the script - ideally -e wouldn't be used at all
any more, for anything ever - it is the wrong concept.
| In so far as POSIX appears to disagree, I think POSIX is violating the
| principle of least astonishment.
I disagree with that - I think that you, and Greywolf (more on his arguments
in another message) are relying too much on your knowledge of how all this
gets implemented, and not upon the shell language itself.
If you were simply looking at this from a language point of view, you'd
be astonished if putting parentheses around any command made any difference
at all to what the command does, or how it behaves.
That is, in normal arithmetic, if someone told you that
4 + 3
could somehow do something different from
(4 + 3)
you'd be amazed.
Note this is not inserting ()'s into an expression (changing "4 + 3 * 2"
into "(4 + 3) * 2") - only putting ()'s around a whole command.
But that's just what you're suggesting should apply to the shell.
Of course, once you "know" that () means a process, another
instance of the shell, which gets fork()'d and run, just like "cc"
or "ls" get fork()'d (etc) - then you can start to look at all this
differently. But that's an implementation detail (a required one perhaps,
but a detail never the less).
| If my intent was to cat the file if it exists, and do nothing if it doesn't
| exist, and to consider neither case to be an error, then I would put the
| following code in the Makefile:
| (cd dir && test -f file && cat file) || true
Very strange - certainly possible, but not what I'd expect, and
certainly only needed when -e applies.
What I'd expect, is that if I intend the shell running a command
to exit if the command fails, I'd write
any-command-group-whatever || exit $?
and make it clear what is required, ignore -e, and have the right thing
happen all the time.
-e was just a hack, to allow scripts to be aborted, without running
all the commands, back in the days when there was no reasonable way
(I think no way at all) to test the exit code of commands and have
the script terminate if a command failed.
It really should have been excised when proper command status testing
was made available.
wrt make - please also note that no original make ever ran a command
with -e set - that was another "improvement" that someone thought was
a good idea somewhere along the line, which really wasn't.
It also broke lots of things - or found a common bug, perhaps.
Back then, make would run the commands with whatever the user's
$SHELL was set to as the shell to use (from the environment,
unless overridden in the Makefile or on the command line).
Perhaps surprisingly, this was so irrelevant for just about any
makefile that no-one really noticed - even those with SHELL=csh ...
Commands in makefiles tended to be fairly simple.
That is, until the -e thing happened - csh's processing of -e
is so bizarre, then makefiles run by csh users started breaking
all over the place (which perhaps they always might have, but
Like Grewolf, I certainly don't always agree with POSIX, some of
what it has done is weird to say the least - but on this issue,
I think they got it exactly right, with the possible exception
of standardising -e at all (it would have been better omitted).
Note that traditional behaviour is different in other ways as well,
it used to be that, with -e
false && false; echo foo
would be silent, as only the LHS of && and || were considered
"special" for -e processing, that is, this was treated as if
it had been
if false; then false; fi; echo foo
which certainly should be silent with -e. POSIX changed that
as well, any command part of a && sequence has its exit status
ignored for -e purposes, including the last one. That's the
right thing to do as well - if I'm writing that kind of logic,
I can trivially add "|| exit" type constructs if that's what
I want to achieve - avoiding it isn't always quite as easy.