Subject: Re: make -j and failure modes
To: Greywolf <greywolf@starwolf.com>
From: Robert Elz <kre@munnari.OZ.AU>
List: tech-userlevel
Date: 12/12/2003 03:52:51
    Date:        Thu, 11 Dec 2003 11:06:13 -0800 (PST)
    From:        Greywolf <greywolf@starwolf.com>
    Message-ID:  <Pine.NEB.4.58.0312111046320.2021@rivendell.starwolf.com>

  | Interesting that I get a non-zero exit back, but the shell does not
  | terminate.

You need neither ()'d commands, nor bash, to get that effect...

$ PS1='Test> ' sh -e
Test> false && false
Test> echo $?
1
Test> false
$ 

The final "false" is just in case anyone believes the "if not interactive"
nonsense in the man page ...  If a simple command fails (even interactively)
the shell exits.   Neither (anything) nor x && y is a simple command.
"false" is.   The "x" and "y" in x && y are specific exceptions to the
"exit immediately", the "anything" is not, if it is simple, but causes the
shell running it to exit.

There's nothing either inconsistent, or unusual here.

  | I think it is.  To have () behave differently than a raw command
  | just because it's ()d makes zero sense.

Hmm ...

	cd /tmp
	(cd /tmp)

"To have () behave differently than a raw command just because it's ()d
makes zero sense."

Really?

Consider the two cases carefully, and I think you'll see that the
two cases are remarkably similar.   In both the internal sub-shell is affected
(in the "false" case, that shell exits, as set -e requests, in the cd
case, its $PWD is altered).   In neither case is the other shell affected
in the same way.

However, if someone told you that they expected (cd /tmp) to behave just
the same as cd /tmp you wouldn't believe them - that's obviously not what
you expect to happen.   The difference is that one you have been used to
for years, and you know why, and how it works - the other is less familiar.

  | It turns out that a failed () still returns an exit status, so perhaps
  | "|| exit $?" might be the most useful solution after all

The "it turns out" is no surprise, all sh grouped commands return the exit 
status of the last command executed.   And yes, explicitly saying what the
script means (even the quite short scripts that make, usually, uses) really
is the best way.

  | How would you have something run, then, that drops instantly dead in its
  | tracks?

I don't think I would, and I doubt anyone else would either.   However, if
sh -e was truly implemented to simply have the shell exit, whenever any
command that is run fails (which I think some implementations did, and
approximates what csh does) then that would at least be consistent.

But then you no longer get to use && or || or if or anything after a while
or ... in the script, as as soon as the conditional command fails, the script
ends.  Useless, but at least consistent.

It is when all the "except for..." stuff was added, to attempt to make "sh -e"
useful, rather than useless, that everything started to get so hard to manage, 
and understand.   That kind of behaviour is usually a pretty good indicator
that the underlying concept is simply the wrong thing to be attempting.

  | Should you be required to jump through hoops to make that happen?

yes, actually, if you really want that.   Most scripts on the other hand
expect to exit only if particular commands fail - not any arbitrary command.

I write stuff like

	cd "$wherever" || exit 1

all the time in my scripts - anything that might fail, and which would then
cause the remainder of the script to be useless -- if the failing command won't
print a suitable error already, it would be cmd || { echo "..." >&2; exit 1; }

kre