Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

exit value of the left side of a pipeline

0 views
Skip to first unread message

Richard H. Gumpertz

unread,
May 23, 1990, 1:07:26 PM5/23/90
to
I have a command, A, which requires some post-processing through filter B.
The exit value of the shell script that invokes A and B, however, should be
the exit value from A. Is there any way to get the exit value of the left
side of a pipeline? What I want is the equivalent of the following:
(A "$@"; RC=$?) | B; exit $RC
but of course setting RC in a sub-shell doesn't make it available to the
containing shell. Also, the "$?" may be evaluated before invoking the
subshell, not in it. { ... } sometimes spawns a subshell, so it won't help
either.

One possibility requires named pipes, which are not available on all systems:
TEMP="/tmp/AB.$$"
trap "fuser -k $TEMP >/dev/null 2>/dev/null; rm -f $TEMP; exit 130" \
1 2 3 13 15
rm -f $TEMP
mknod $TEMP p
A "$@" <$TEMP &
B >$TEMP
RC=$?
rm -f $TEMP
trap 1 2 3 13 15
exit $RC
Another possibility uses a temporary file for passing the exit code:
TEMP="/tmp/AB.$$"
trap "rm -f $TEMP; exit 130" 1 2 3 13 15
echo 'A "$@"; echo $? >'$TEMP | sh -s "$@" | B
exit `cat $TEMP; rm -f $TEMP`
This second script has the significant problem that the command A cannot read
the standard input of the shell script.

What alternatives are there, preferably ones that don't require named pipes,
that still allow A to read the standard input of the shell script? If
nothing else, what can I do to simplify the first script? There ought to be
a simple way to filter the output of a command but still capture it's exit
value!

My NEWS processing is not entirely reliable. Therefore, please also send a
copy of any followup postings to me by e-mail.

--
==========================================================================
| Richard H. Gumpertz r...@CPS.COM (913) 642-1777 or (816) 891-3561 |
| Computer Problem Solving, 8905 Mohawk Lane, Leawood, Kansas 66206-1749 |
==========================================================================

Maarten Litmaath

unread,
May 23, 1990, 6:07:24 PM5/23/90
to
In article <5...@cpsolv.CPS.COM>,
r...@cpsolv.CPS.COM (Richard H. Gumpertz) writes:
)I have a command, A, which requires some post-processing through filter B.
)The exit value of the shell script that invokes A and B, however, should be
)the exit value from A. Is there any way to get the exit value of the left
)side of a pipeline? What I want is the equivalent of the following:
) (A "$@"; RC=$?) | B; exit $RC
)but of course setting RC in a sub-shell doesn't make it available to the
)containing shell.

Indeed.

)Also, the "$?" may be evaluated before invoking the
)subshell, not in it.

Only in a buggy implementation...

){ ... } sometimes spawns a subshell, so it won't help
)either.

Where did I hear this before? :-) :-(

[ugly workaround deleted]

Here's a hack that ought to work on every sh implementation since V7;
it doesn't use a temp file!

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 a subshell with fd 3 closed (it doesn't need 3),
# and stdout connected to the pipe.
# In this subshell execute `A' with fd 4 closed as well.
# Echo the exit status to the remembered captured stdout.
# Before executing `B', connect its stdin to the pipe, its stdout
# to the original stdout, and close fd 3 and 4.

RC=`
exec 4>&1
(A "$@" 4>&-; echo $? >&4) 3>&- | B >&3 3>&- 4>&-
`

exit $RC

Piece of cake. :-)
--
Antique fairy tale: Little Red Riding Hood. |Maarten Litmaath @ VU Amsterdam:
Modern fairy tale: Oswald shot Kennedy. |ma...@cs.vu.nl, uunet!cs.vu.nl!maart

Wietse Z. Venema

unread,
May 24, 1990, 7:57:19 AM5/24/90
to
In <5...@cpsolv.CPS.COM>, r...@cpsolv.CPS.COM (Richard H. Gumpertz) writes:
>I have a command, A, which requires some post-processing through filter B.
>The exit value of the shell script that invokes A and B, however, should be
>the exit value from A.

This reminds me of a related problem with pipe lines, where one needs an
indication of "success" or "failure". "success" means that *each* stage
of a pipe line completed with zero exit status. The following idiom may
be useful for the original problem as well:

trap 'exit 1' 15

(A || kill $$) |
(B || kill $$) |
...

Larry Wall

unread,
May 24, 1990, 6:03:25 PM5/24/90
to
In article <67...@star.cs.vu.nl> ma...@cs.vu.nl (Maarten Litmaath) writes:
: In article <5...@cpsolv.CPS.COM>,

: r...@cpsolv.CPS.COM (Richard H. Gumpertz) writes:
: )I have a command, A, which requires some post-processing through filter B.
: )The exit value of the shell script that invokes A and B, however, should be
: )the exit value from A. Is there any way to get the exit value of the left
: )side of a pipeline? What I want is the equivalent of the following:
: ) (A "$@"; RC=$?) | B; exit $RC
: )but of course setting RC in a sub-shell doesn't make it available to the
: )containing shell.
:
: Here's a hack that ought to work on every sh implementation since V7;

: it doesn't use a temp file!
:
: 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 a subshell with fd 3 closed (it doesn't need 3),
: # and stdout connected to the pipe.
: # In this subshell execute `A' with fd 4 closed as well.
: # Echo the exit status to the remembered captured stdout.
: # Before executing `B', connect its stdin to the pipe, its stdout
: # to the original stdout, and close fd 3 and 4.
:
: RC=`
: exec 4>&1
: (A "$@" 4>&-; echo $? >&4) 3>&- | B >&3 3>&- 4>&-
: `
:
: exit $RC
:
: Piece of cake. :-)

If you're not into large numbers of small numbers, how 'bout a one-liner:

perl -e 'open(X, "| B"); open(STDOUT, ">&X"); exec "A";'

Or you could write a little script to grab an arbitrary status out of
the middle of a command, to be invoked something like:

statusof "A | B | C |# D #| E | F | G"

and the script:

#!/usr/bin/perl
($pre,$cmd,$post) = split(/#/,shift);
open(I,$pre); open(STDIN, "<&I");
open(O,$post); open(STDOUT,">&O");
exec $cmd;

These seem fairly self-explanatory to me.

Larry Wall
lw...@jpl-devvax.jpl.nasa.gov

0 new messages