Apparently this behaviour has bothered me in the past as well, and I didn’t realize until I googled just now for an answer… I’ve never really thought to hard about this, but it turns out that bash’s return code checking for pipelines is rather dumb. Specifically, bash checks the return code of the last command in the pipeline, not the entire pipeline. For example:
mikal@mstill:~$ exit 1 | exit 2 mikal@mstill:~$ echo $? 2
We get the return code of the last process in the pipeline. Perhaps fair enough… Then again:
mikal@mstill:~$ exit 1 | exit 0 mikal@mstill:~$ echo $? 0
Here we get the return code of the final process again, which masks the error in the first process from being reported. You can get the return codes of all processes in the pipe like this:
mikal@mstill:~$ exit 1 | exit 2 mikal@mstill:~$ echo ${PIPESTATUS[@]} 1 2
And then if you assume that the sum of all return codes will report if an error occurred:
mikal@mstill:~$ exit 1 | exit 0 mikal@mstill:~$ expr `echo ${PIPESTATUS[@]} | sed 's/ / + /g'` 1
Which is evil, but does what I want. Is there a less evil way of doing this?