Bash pipe exit codes

cog on 2004-05-26T09:35:40

So the question for the day is:

The exit code of a pipe is the result of the last executed command...

How do I know if any of the other commands originated an exit code different from 0? :-| Is this possible at all?

Some examples (with Perl ;-) ):

    perl -e 'exit 3' | perl -e 'exit 2'
    exit code => 2

    perl -e 'exit 3' | perl -ne 'exit 2'
    exit code => 3

    perl -e 'exit 3' | perl -e 'exit 0'
    exit code => 0

How can I get that 3 on the first and last examples? :-|


Errors from shell pipes are painful

bluto on 2004-05-26T13:17:25

... but you can solve this at least one of two ways. You can build the pipe yourself and check the exit code from all of the children. You can also try something like this from the command line...

perl -e 'exit 1';rc1=$? | perl -e 'exit 0'; rc2=$? echo $rc1

... which seems to work for me.

Correction...

bluto on 2004-05-26T13:20:09

The 'echo $rc1' should appear on the following line, obviously...

Re:Errors from shell pipes are painful

cog on 2004-05-26T13:28:24

I get the idea...

However, it seems parens are needed, no? Something like:

(perl -e 'exit 1';rc1=$?) | perl -e 'exit 0';rc2=$?

Because otherwise the second command on the pipe will only get the result of the atribution to rc1 ;-)

But that works :-)

Thanks a lot for the idea :-)

Re:Errors from shell pipes are painful

bluto on 2004-05-26T17:48:15

Ugh, and it's not even Monday. Yeah I think you are right. As you can tell my shell scripting ability is pretty rusty -- probably since I use perl a lot more often nowadays...

Re:Errors from shell pipes are painful

jmm on 2004-05-26T23:37:39

Nope. When a command is a pipeline, all but the last portions are run by a forked copy of the original shell - the assignment to rc1 will be done by that sub-shell and will not affect any setting of rc1 in the parent shell.

You have to report the status out of band and catch it separately.
(perl -e 'exit 1'; echo rc1=$? >> /tmp/status ) |
(perl -e 'exit 5'; echo rc2=$? >> /tmp/status ) |
perl -e 'exit 99'
rc3=$?
`cat /tmp/status`
(You can echo those status assignments to stderr or stdout and catch them on the original command line with some additional trickery - left as an exercise to a bear of greater brain.)