How to get both PIPESTATUS and output in bash script

You could do this:

TM_LOCAL=$(ls -l --time-style=long-iso ~/.vimrc | \
             awk '{ print $6" "$7 }' ; exit ${PIPESTATUS[0]} )

Then $? will be the return code from ls. This doesn't work if you need the return code from more than one of the pipe parts (but you could split the pipeline if the output isn't too large, as it is here).

Here's a rather expensive way of getting the full PIPESTATUS array and the output. Not very elegant, but haven't found anything else:

result=$(echo -e "a\nb\nc" | \
          ( cat ; exit 1 ) | \
          ( cat ; exit 42 ) ; echo ${PIPESTATUS[@]})
output=$(head -n -1 <<< "$result")
status=($(tail -n 1 <<< "$result"))
echo "Output:"
echo "$output"
echo "Results:"
echo "${status[@]}"

Which gives:

Output:
a
b
c
Results:
0 1 42

Use set -o pipefail in bash to get the right-most non-zero exit code in a piped command sequence as $?. From man bash:

If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.

Then you can simply access $?. Use set +o pipefail to disable again.


I assume the issue here is that PIPESTATUS goes away in its entirety as soon as you execute a command. You can get the complete PIPESTATUS array in bash version 2 or above this way:

declare -a status
status=(${PIPESTATUS[@]})

Then access ${status[0]}, ${status[1]}, etc.

Tags:

Bash

Pipe