[comp.unix] Nasty little shell syntax problem for a Wizard

frank@odetics.com (Frank Merrow) (11/15/90)

I am pretty good at shell, but this one has me a little stumped:

I am running a command out of "make" so the condition code is important in what
I am doing . . .

Step 1

gcc <parms> || (abort_script;exit 1)

This statement lets me do some post processing when the compiler finds an error.

Step 2

gcc is generating a SINGLE warning message that I want to suppress, BUT I want
the warning in all cases except for one VERY special one.  So what I want to
do is something like:

gcc <parms> 2>&1 | egrep -v "<re>"

This has problems because the condition code that make seems to use is the
one from the egrep NOT the gcc.

Problem:

Conceptually what I want is something like:

gcc <parms> 2>&1 | egrep -v "<re>" || (abort_script;exit 1)

Except that I want the || to use the condition code from the gcc (NOT the egrep)
AND I want the condition code of the whole expression to be OK if the compile
is OK or ERROR if the compile has an error.

Note one possible solution I thought of was

gcc <parms> 2>&1 > temp_file || (abort_script;exit1)
egrep -v "<re>" temp_file

The problem with this solution is that on Error the errors do NOT appear on
stdout because the egrep doesn't get done.

Another solution is to actually put a compound "if" shell statement in the
makefile.  My make does support this, but I personally think it looks
tacky and would prefer to avoid this solution.

Any shell wizards got a slick solution to this?

Frank
frank@odetics.com or uunet!odetics!frank

maart@cs.vu.nl (Maarten Litmaath) (11/21/90)

)...
)gcc <parms> 2>&1 | egrep -v "<re>"
)
)This has problems because the condition code that make seems to use is the
)one from the egrep NOT the gcc.

To obtain the exit status of a command in the middle of a pipeline you
have to resort to things like this:

	a | b | (c; echo $? > /tmp/ecode$$) | d | e

	if [ `cat /tmp/ecode$$` != 0 ]
		...

If your OS supports named pipes (FIFOs) you could do this:

	TMPFIFO=/tmp/myfifo
	mknod $TMPFIFO p
	a | b | c > $TMPFIFO &
	< $TMPFIFO d | e
	wait $!
	echo "The exit status of c is $?"

Still an ugly temp file hack.  To avoid the temp file there's this gross
construct:

	exec 3>&1	# Make file descriptor 3 a duplicate of stdout.

	# Below: make fd 4 a dup of the new stdout, i.e. the output stream
	# that's being captured.
	# Then execute each but the last component of the pipeline with
	# fd 3 closed; fd 4 is closed for each component but the one whose
	# exit status we want to capture.
	# The exit status is echoed to the remembered captured stdout.
	# Before the last component of the pipeline is started, its stdout
	# is connected to the original stdout, after which fd 3 can be
	# closed for this command as well.

	status=`
		exec 4>&1
		a 4>&- 3>&- |
		b 4>&- 3>&- |
		(c 4>&-; echo $? >&4) 3>&- |
		d 4>&- 3>&- |
		e 4>&- >&3 3>&-
	`

	exec 3>&-	# We don't need it anymore.

	echo "The exit status of c is $status"

In the case of a Makefile, however, we can easily avoid this whole mess:

	# Makefile for target

	target:	dependencies
		(gcc <parms> 2>&1 || kill $$$$) | egrep -v "<re>"

Make sure the final part of the pipeline doesn't exit without having
read all of the output of the first stage, else the latter might be killed
with a SIGPIPE, as illustrated in the following example:

	foo:
		(cat /etc/termcap; kill $$$$) | true

Furthermore to prevent the `egrep' from getting killed instead of the
shell started by `make', you may want to use this instead:

		(gcc <parms> 2>&1 || kill $$$$) | (egrep -v "<re>"; true)
--
nreadwin@micrognosis.co.uk (Neil Readwin) on "snuff" films:
"Seen one ? I was *in* one. They tortured me horribly and then killed me
 with a single shot in the back of the head ! Following total brain death
 I gave up acting and became a VMS hacker."

jan@golf.canberra.edu.au (Jan Newmarch) (11/21/90)

>Conceptually what I want is something like:
>gcc <parms> 2>&1 | egrep -v "<re>" || (abort_script;exit 1)
>Except that I want the || to use the condition code from the gcc (NOT the egrep)
>AND I want the condition code of the whole expression to be OK if the compile
>is OK or ERROR if the compile has an error.

The shell variable `?' holds the exit code of the last instruction executed,
so you could run your gcc, save the exit code, run egrep and the exit:

	gcc > ...
  	code=$?
	egrep ...
	exit $code

+----------------------+---+
  Jan Newmarch, Information Science and Engineering,
  University of Canberra, PO Box 1, Belconnen, Act 2616
  Australia. Tel: (Aust) 6-2522422. Fax: (Aust) 6-2522999

  ACSnet: jan@ise.canberra.edu.au
  ARPA:   jan%ise.canberra.edu.au@uunet.uu.net
  UUCP:   {uunet,ukc}!munnari!ise.canberra.edu.au!jan
  JANET:  jan%au.edu.canberra.ise@EAN-RELAY

+--------------------------+

hartman@ide.com (Robert Hartman) (11/21/90)

In article <2258@megadon.UUCP> uunet!odetics!frank (Frank Merrow) writes:
>...
>I am running a command out of "make" so the condition code is important in what
>I am doing . . .
>
>Step 1
>
>gcc <parms> || (abort_script;exit 1)
>
>This statement lets me do some post processing when the compiler finds an error.
>
>Step 2
>
>gcc is generating a SINGLE warning message that I want to suppress, BUT I want
>the warning in all cases except for one VERY special one.  ...

[deleted discussion of options for getting around fact that return code from a
pipeline is that of the last command in the pipeline]

This seems like the wrong tack to me.  I'd suggest putting the code to filter
out the undesired instances of the error message in the post-processing script,
invoking it as follows:

	gcc ... 2>&1 gcc.out || (abort_script < gcc.out; exit 1)

Between make and the shell there are all sorts of clever things a person can
do.  However, it is often best not to (as anyone who's had to modify some of
_my_ early makefiles will agree).

-r