Subject: Re: make -j and failure modes
To: James Chacon <jmc@NetBSD.org>
From: Robert Elz <kre@munnari.OZ.AU>
List: tech-userlevel
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...

jmc@NetBSD.org said:
  | 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
exclusion carefully.

That is

	if false; true
	then
		echo fine
	fi

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
command.

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
exit.

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.

apb@cequrux.com said:
| 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).

apb@cequrux.com said:
| 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
never mind).

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.

kre