Newsgroups: comp.unix.shell
Subject: Re: Propagating Exit Status in a Pipeline
References: <[email protected]>
<01bc9480$11d92720$88be2399@hp-customer>
From: [email protected]
Lines: 104
X-Newsreader: Gnus v5.3/Emacs 19.34
Date: 20 Jul 1997 09:40:01 -0700
Message-ID:
--text follows this line--
if you want the exit status of cmd1, in cmd1 |cmd2 |cmd3, try
something like the following (untested):
exec 5>&1 # store original stdout
result=`
(
(
cmd1;
echo $? 1>&3 # echo the exit status of cmd1 into descriptor
# 3, the stdout of the backticks, so it gets
# stored into result
) |
cmd2 |
cmd3
)
3>&1 # copy the stdout of the backticks to descriptor 3 (for
# use by the echo command)
1>&5 # make the stdout of cmd3 be the original stdout
`
exec 5>&-
$result now contains the exit status of cmd1.
to understand how this works, you have to be aware that the shell
forks from right to left, interpreting the redirections from left to
right inside each command. so, what happens is:
the global stdout is saved to desc 5.
the stdout being assigned to result (originally destined to be the
stdout of cmd3) is saved to desc 3.
the stdout of cmd3 is redirected to the global stdout (so you'll see
it, or it'll end up in whatever file you redirected the script into,
or whatever).
then cmd2 and cmd are forked, and all the commands begin to run more
or less simultaniously.
after cmd1 finishes executing, the echo command's stdout is redirected
into desc 3, so whatever it prints will be assigned to result.
$? contains the exit status of cmd1, so it is what is prints is the
exit status of cmd1.
if you want to assign the output of the pipeline to a variable, and
get the exit status of something other than the last command, a few
named pipes could come in handy...
TMPFIFO1=/tmp/fifo1.$$
TMPFIFO2=/tmp/fifo2.$$
mknod $TMPFIFO1 p
mknod $TMPFIFO2 p
(cmd1; result=$?; exec 1>&-; echo $result 1> $TMPFIFO2) |
cmd2 |
cmd3 > $TMPFIFO1 &
output=`cat $TMPFIFO1`
result=`cat $TMPFIFO2`
rm -f $TMPFIFO1 $TMPFIFO2
the theory here is that by closing the stdout of the subshell cmd1 is
running in, cmd2 will get an EOF, and eventually cmd2 and cmd3 will
terminate, causing the 'cat $TMPFIFO1' to terminate (so we don't end
up in deadlock). meanwhile, the 'echo $result 1> $TMPFIFO2' will have
blocked, waiting for the 'cat $TMPFIFO2'
the 'result' variable in the cmd1 subshell is separate (since it's in
a separate shell). it is required so the echo echoes the result of
cmd1 and not the result of 'exec 1>&-', which will pretty much always
be true (ain't shell scripting grand? where else is 0 true and 1
false?). also, by using more fifos, you could use this technique to
capture the exit status of more than one command in the same pipeline.
as for getting the exit status of an rsh command, if you don't need
any output, just put an 'echo $?' at the end of it, and save the
output.
if you *do* need output, as long as it's text, and all the lines end
in a newline, you could just make the last line be the exit
status... something like:
OUTPUTFILE=/some/file/name
result=`rsh somehost 'somecommand; echo $?' | (
IFS="" # needed to maintain leading/trailing tabs in lines
: > $OUTPUTFILE
read oldline
while read line
do
echo "$oldline" >> $OUTPUTFILE
oldline="$line"
done
echo "$oldline"
)
`
best of luck,
andru