You can use a named pipe and connect the two processes manually. Start them in the opposite order, so the left-hand side runs in the foreground and you get its exit status from $?
as usual.
#!/bin/sh
dir=$(mktemp -d)
mkfifo "$dir/p"
cat < "$dir/p" > /dev/null &
( echo foo; exit 12; ) > "$dir/p"
echo "exit status: left: $?"
rm -r "$dir"
Or if you want both, get the PID of the background process from $!
and wait
to get the exit status.
#!/bin/sh
dir=$(mktemp -d)
mkfifo "$dir/p"
( echo foo; exit 12; ) > "$dir/p" & # left-hand side
pidleft=$!
( cat; exit 34; ) < "$dir/p" > /dev/null & # right-hand side
pidright=$!
wait "$pidleft"; exitleft=$?
wait "$pidright"; exitright=$?
echo "exit status: left: $exitleft right: $exitright"
rm -r "$dir"
You could still leave the second part of the pipe in the foreground, I just wanted to do it symmetrically.
You could also e.g. store the exit status to files, and fetch them from there:
#/bin/sh
( somecmd; echo "$?" > exit1 ) | ( cat; echo "$?" > exit2)
echo "exit status: left: $(cat exit1) right: $(cat exit2)"
I don't think a named pipe will be of much use here, since the exit status is only a couple of bytes. The shell will wait for the pipeline to complete before trying to read exit1
and exit2
on the second line.
If you want to use named pipes instead, you'll need to put the pipeline in the background, since the writes to the pipes block until the reading side is opened.
#/bin/sh
mkfifo exit1 exit2
( somecmd; echo "$?" > exit1 ) | ( cat; echo "$?" > exit2) &
echo "exit status: left: $(cat exit1) right: $(cat exit2)"
However, if the cat
s reading the pipes don't run for some reason, the
subshells writing to them will block indefinitely in the background.