[comp.unix.questions] sh

montnaro@sprite (Skip Montanaro) (02/06/88)

I want to execute a Bourne shell pipeline using system(3) and get a
non-zero exist status from sh(1) if any of the elements of the pipe
return non-zero statuses.

As a concrete example, we have a remote nroff/troff execution
evironment on our Suns called format that is accessible from our VMS
VAXes. The user never sees the UNIX side of things, just gives a
filename argument to format:

	format whiffle.nro

What format does is rummage through the input file and transfer it and
any other included files to the Sun, and send a command like:

	tbl whiffle.nro | neqn | nroff -mm > whiffle.prf

When the command terminates, the output file is transferred back to
the VAX for printing.

My problem occurs when either the tbl or neqn segments of the pipe
terminate with a non-zero exit status. The system(3) call never sees
those errors, since sh(1) returns the exit status of the last command
in the pipe. Can someone offer a suggestion regarding how I might get
sh(1) to return the exit status of the first (or any) segment of the
pipe that is non-zero, without losing the simplicity of a pipeline. (I
can write a shell script to do what I want.)

Thanks,

Skip (montanaro@ge-crd.arpa, uunet!steinmetz!sprite!montanaro)

jdpeek@rodan.acs.syr.edu (Jerry Peek) (03/08/90)

I'm using these lines in a BSD-type Bourne shell script.  They give me
the last command line argument in $last and the others in $first:

    last="`expr \"$*\" : '.* \(.*\)'`"   # LAST ARGUMENT
    first="`expr \"$*\" : '\(.*\) .*'`"  # ALL BUT LAST ARG

Seems like, years ago, I needed to put doublequotes around the backquotes
to protect any spaces from the shell.  So, I write quoting nightmares like
that one.  But maybe I've got over-quoting paranoia. :-)  Would this be safe?

    last=`expr "$*" : '.* \(.*\)'`   # LAST ARGUMENT
    first=`expr "$*" : '\(.*\) .*'`  # ALL BUT LAST ARG

Our BSD-type sh(1) man page seems to say that it's okay (?):

    After parameter and command  substitution,  any  results  of
    substitution  are scanned for internal field separator char-
    acters (those found in $IFS) and split into  distinct  argu-
    ments  where such characters are found...

I'd like this script to be portable.  Is there any Bourne shell
(including mine!) that will choke on the less-quoted version?  Thanks.

--Jerry Peek; Syracuse University Academic Computing Services; Syracuse, NY
  jdpeek@rodan.acs.syr.edu, JDPEEK@SUNRISE.BITNET        +1 315 443-3995

maart@cs.vu.nl (Maarten Litmaath) (03/09/90)

In article <2387@rodan.acs.syr.edu>,
	jdpeek@rodan.acs.syr.edu (Jerry Peek) writes:
)...
)    last="`expr \"$*\" : '.* \(.*\)'`"   # LAST ARGUMENT
)    first="`expr \"$*\" : '\(.*\) .*'`"  # ALL BUT LAST ARG
)
)Seems like, years ago, I needed to put doublequotes around the backquotes
)to protect any spaces from the shell.  [...]

Indeed.
Let's assume the IFS characters are space, tab and newline, and no argument
contains such characters; then you could remove the outer double quotes.
Example:

	$ set a b c
	$ last=`expr "$*" : '.* \(.*\)'`
	$ first=`expr "$*" : '\(.*\) .*'`
	$ echo "=$first=$last="
	=a b=c=

This should work too (more consistent, IMHO):

	$ last=`expr "$*" : '.* \\(.*\\)'`

Right, let's try some funny arguments:

	$ set a '   ' b
	$ last=`expr "$*" : '.* \(.*\)'`
	$ first=`expr "$*" : '\(.*\) .*'`
	$ echo "=$first=$last="
	=a    =b=
	$ /bin/echo `expr "$*" : '\(.*\) .*'` | od -a
	0000000    a  nl
	0000002

Huh?!  In an assignment the results of command substitution are NOT scanned
for IFS characters!  (At least on SunOS 4.0.3c and 4.3BSD.)  All the SunOS
manual has to say about assignments:

     Keyword parameters (also known as variables) may be assigned
     values by writing:

          name=value [ name=value ] ...

     Pattern-matching is not performed on value.

So:
	$ a=*
	$ echo "$a"
	*

Anyway, here's an example showing the effect of an embedded space in the last
argument:

	$ set a b c' 'd
	$ last=`expr "$*" : '.* \(.*\)'`
	$ first=`expr "$*" : '\(.*\) .*'`
	$ echo "=$first=$last="
	=a b c=d=
--
  "Belfast: a sentimental journey to the Dark Ages - Crusades & Witchburning
  - Europe's Lebanon - Book Now!" | maart@cs.vu.nl,  uunet!mcsun!botter!maart