I don't have enough reputation to comment, but the accepted answer was missing a closing }
on line 5.
After fixing this, the code will throw a -ne: unary operator expected
error, which points to a problem: PIPESTATUS
is overwritten by the conditional following the if
command, so the return value of process_commands
will never be checked!
This is because [ ${PIPESTATUS[0]} -ne 0 ]
is equivalent to test ${PIPESTATUS[0]} -ne 0
, which changes $PIPESTATUS
just like any other command. For example:
return0 () { return 0;}
return3 () { return 3;}
return0 | return3
echo "PIPESTATUS: ${PIPESTATUS[@]}"
This returns PIPESTATUS: 0 3
as expected. But what if we introduce conditionals?
return0 | return3
if [ ${PIPESTATUS[0]} -ne 0 ]; then
echo "1st command error: ${PIPESTATUS[0]}"
elif [ ${PIPESTATUS[1]} -ne 0 ]; then
echo "2nd command error: ${PIPESTATUS[1]}"
else
echo "PIPESTATUS: ${PIPESTATUS[@]}"
echo "Both return codes = 0."
fi
We get the [: -ne: unary operator expected
error, and this:
PIPESTATUS: 2
Both return codes = 0.
To fix this, $PIPESTATUS
should be stored in a different array variable, like so:
return0 | return3
TEMP=("${PIPESTATUS[@]}")
echo "TEMP: ${TEMP[@]}"
if [ ${TEMP[0]} -ne 0 ]; then
echo "1st command error: ${TEMP[0]}"
elif [ ${TEMP[1]} -ne 0 ]; then
echo "2nd command error: ${TEMP[1]}"
else
echo "TEMP: ${TEMP[@]}"
echo "All return codes = 0."
fi
Which prints:
TEMP: 0 3
2nd command error: 3
as intended.
Edit: I fixed the accepted answer, but I'm leaving this explanation for posterity.