Signup/Sign In
Ask Question
Not satisfied by the Answer? Still looking for a better solution?

Get exit status of process that's piped to another

I have two processes foo and bar, connected with a pipe:
$ foo | bar


bar always exits 0; I'm interested in the exit code of foo. Is there any way to get at it?
by

2 Answers

akshay1995
bash and zsh have an array variable that holds the exit status of each element (command) of the last pipeline executed by the shell.

If you are using bash, the array is called PIPESTATUS (case matters!) and the array indicies start at zero:

$ false | true
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
1 0

If you are using zsh, the array is called pipestatus (case matters!) and the array indices start at one:

$ false | true
$ echo "${pipestatus[1]} ${pipestatus[2]}"
1 0

To combine them within a function in a manner that doesn't lose the values:

$ false | true
$ retval_bash="${PIPESTATUS[0]}" retval_zsh="${pipestatus[1]}" retval_final=$?
$ echo $retval_bash $retval_zsh $retval_final
1 0

Run the above in bash or zsh and you'll get the same results; only one of retval_bash and retval_zsh will be set. The other will be blank. This would allow a function to end with return $retval_bash $retval_zsh (note the lack of quotes!).
pankajshivnani123
There are 3 common ways of doing this:

Pipefail
The first way is to set the pipefail option (ksh, zsh or bash). This is the simplest and what it does is basically set the exit status $? to the exit code of the last program to exit non-zero (or zero if all exited successfully).

$ false | true; echo $?
0
$ set -o pipefail
$ false | true; echo $?
1


$PIPESTATUS
Bash also has an array variable called $PIPESTATUS ($pipestatus in zsh) which contains the exit status of all the programs in the last pipeline.

$ true | true; echo "${PIPESTATUS[@]}"
0 0
$ false | true; echo "${PIPESTATUS[@]}"
1 0
$ false | true; echo "${PIPESTATUS[0]}"
1
$ true | false; echo "${PIPESTATUS[@]}"
0 1

You can use the 3rd command example to get the specific value in the pipeline that you need.

Separate executions
This is the most unwieldy of the solutions. Run each command separately and capture the status

$ OUTPUT="$(echo foo)"
$ STATUS_ECHO="$?"
$ printf '%s' "$OUTPUT" | grep -iq "bar"
$ STATUS_GREP="$?"
$ echo "$STATUS_ECHO $STATUS_GREP"
0 1

Login / Signup to Answer the Question.