chris@mimsy.UUCP (Chris Torek) (10/02/88)
In article <826@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes: >command1 || command2 # do command2 only if command1 failed >command1 && command2 # do command2 only if command1 succeeded >while command1; do commands; done # while command1 succeeds do the commands >until command1; do commands; done # until command1 succeeds do the commands >if command1; do commands; done # if command1 succeeds do the commands > >And now we're at it: > >set -e # exit - if the shell's not interactive - as soon as a command fails With the exception of `set -e', these constructs exist in csh as well, although the syntax differs: command1 || command2 command1 && command2 while ({ command1 }) commands end while (! { command1 }) commands end if ({ command1 }) then commands endif The parentheses around { command1 } may sometimes be elided. But beware!: the effect of && and || were reversed in the 3BSD C shell, and are still reversed in some derivative C shells. (It is fixed in 4.3BSD; I am not sure how far back the rot goes.) Regarding `set -e': again, beware! Old versions of /bin/sh will exit if the test portion of an `if', `while', or `until' returns a nonzero status, if `-e' is set. (These are fixed in 4.3BSD-tahoe.) In addition, `command1 || command2' will exit if command1 fails. (It will also exit if command2 fails, but that seems sensible. I believe SysV's /bin/sh does *not* exit if command2 fails. If this is considered correct behaviour, let me know, because I just `fixed' this to work the way I think seems sensible.) Incidentally, this bug in the 4BSD `/bin/sh'es accounts for makefile lines like -[ -d ${DESTDIR}${LIBDIR} ] || mkdir ${DESTDIR}${LIBDIR} where the `-' before the test `[' seems erroneous: it tells make to run sh without the -e flag, so that the mkdir can happen. An alternate workaround is to use set +e; [ -d ${DESTDIR}${LIBDIR} ] || mkdir ${DESTDIR}${LIBDIR} which has the advantage that if mkdir fails, make stops. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
gwyn@smoke.ARPA (Doug Gwyn ) (10/03/88)
In article <13810@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
-Regarding `set -e': again, beware! Old versions of /bin/sh will
-exit if the test portion of an `if', `while', or `until' returns
-a nonzero status, if `-e' is set. (These are fixed in 4.3BSD-tahoe.)
-In addition, `command1 || command2' will exit if command1 fails.
-(It will also exit if command2 fails, but that seems sensible.
-I believe SysV's /bin/sh does *not* exit if command2 fails. If
-this is considered correct behaviour, let me know, because I just
-`fixed' this to work the way I think seems sensible.)
The correct behavior is for "failure || failure" to count as an error
with respect to "set -e", and the other combinations of operands to ||
to not count as an error. BRL's SVR2-based shell works this way; I
seem to recall that there was a bug in the eflag handling that had to
be fixed, although it might not have involved || (I don't remember).
Obviously you don't want to make your shell scripts depend on this if
you're concerned about portability.
prl@iis.UUCP (Peter Lamb) (10/04/88)
In article <13810@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >Regarding `set -e': again, beware! Old versions of /bin/sh will >exit if the test portion of an `if', `while', or `until' returns >a nonzero status, if `-e' is set. (These are fixed in 4.3BSD-tahoe.) >In addition, `command1 || command2' will exit if command1 fails. >(It will also exit if command2 fails, but that seems sensible. >I believe SysV's /bin/sh does *not* exit if command2 fails. If >this is considered correct behaviour, let me know, because I just >`fixed' this to work the way I think seems sensible.) > >In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) >Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris And some not-so-old /bin/sh's. This is one of my pet peeves with Ultrix. Up to and including Ultrix 2.2 DEC's /bin/sh does just this, which makes makefiles using conditionals difficult to do right. DEC's /bin/sh5 (SysV shell) works correctly in this respect, but... because DEC added the { command ; command } syntax to their shell, and then put this in just about every critical shell script on the system, you can't make the SysV shell /bin/sh (or rather you can, but you won't be able to boot multi-user nor load DEC layered products :-) . And just to support Chris' case that sh -e should not exit if the command in a conditional returns non-zero status; if you have a conditional, it is usually because you *EXPECT* the thing to fail sometimes, otherwise you wouldn't have bothered! -- Peter Lamb uucp: seismo!mcvax!ethz!prl eunet: prl@ethz.uucp Tel: +411 256 5241 Institute for Integrated Systems ETH-Zentrum, 8092 Zurich
leo@philmds.UUCP (Leo de Wit) (10/05/88)
In article <639@eiger.iis.UUCP> prl@iis.UUCP (Peter Lamb) writes: [ ]... |And just to support Chris' case that sh -e should not exit if the |command in a conditional returns non-zero status; | |if you have a conditional, it is usually because you *EXPECT* the |thing to fail sometimes, otherwise you wouldn't have bothered! Of course, but you must take two other things into account: 1) the conditional is not the exit status of a (1) command, but of a command list. I can even write something down like: if <shell script here> then <other stuff here> fi and put a whole shell script into the conditional clause (not that this is common practice). Now do you want -e to be turned off for the whole clause (see also beneath) ?? 2) -e is used when successfull execution of the commands in a script is a must; take for instance the 'Make' example. Why would the commands in the commandlist of a conditional clause suddenly be all that different? If they are, they should be executed by a different shell (my humble opinion). A minimal change to the meaning of -e could add the functionality required without hardly breaking existing code (i.e. the code that already depends on shells that turn off -e for conditionals): The last command of the conditional clause's command list should not cause an exit if it fails and -e is set. a) Since most clauses are just a simple command (e.g. test) this works OK in these cases. b) The change allows termination of the script on all other commands in the command list, thus respecting the meaning of -e. c) If you don't want the b)-haviour, there are some alternatives: you can execute the commands in a subshell; note that this has to provide for a means of turning off -e which the BSD /bin/sh doesn't seem to have, since -e is inherited. Invoking this shell by sh -c seems to avoid this problem: if sh -c "<non-critical commands here>"; then etc; fi Just some oil to keep the fire bourning... 8-) Leo.
prl@iis.UUCP (Peter Lamb) (10/07/88)
In article <831@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes: >In article <639@eiger.iis.UUCP> prl@iis.UUCP (Peter Lamb) writes: >|if you have a conditional, it is usually because you *EXPECT* the >|thing to fail sometimes, otherwise you wouldn't have bothered! > >Of course, but you must take two other things into account: >1) the conditional is not the exit status of a (1) command, but of a >command list. I can even write something down like: >if ><shell script here> >then ><other stuff here> >fi >and put a whole shell script into the conditional clause (not that this >is common practice). Now do you want -e to be turned off for the whole >clause (see also beneath) ?? Yes. >A minimal change to the meaning of -e could add the functionality >required without hardly breaking existing code (i.e. the code that >already depends on shells that turn off -e for conditionals): >The last command of the conditional clause's command list should not >cause an exit if it fails and -e is set. This seems unnecessarily complicated. I would settle for *either* the BSD /bin/sh behaviour (always exit on -e) or for the SysV behaviour (don't exit if the return status of the list is `tested') provided a) It was always the same and b) It was clearly documented. What really bugs me about Ultrix is not so much the -e behavior as their totally crazy hacking of /etc/rc* and /etc/setld and other critical system scripts to put in their cutesy [ -f totally_nonstandard ] && { bizarre ; whacky } replacement of the standard `if' tests, so that I *can't* use the SysV shell (also provided by DEC in Ultrix as /bin/sh5) as /bin/sh because I won't be able to boot my machine multiuser any more! -- Peter Lamb uucp: seismo!mcvax!ethz!prl eunet: prl@ethz.uucp Tel: +411 256 5241 Institute for Integrated Systems ETH-Zentrum, 8092 Zurich