LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   bash: pass a return value down a pipe? (https://www.linuxquestions.org/questions/programming-9/bash-pass-a-return-value-down-a-pipe-4175443885/)

hydraMax 01-02-2013 06:54 PM

bash: pass a return value down a pipe?
 
Hi. I am wondering: is it possible somehow to pass a return value down a pipeline in bash (or perhaps another shell scripting language?) A simple example would be something like so:

Code:

false | echo $?
Which would output "1". However, this doesn't work because $? "expands to the exit status of the most recently executed foreground pipeline", which would be the pipeline before the one currently executing.

I was thinking that, if it were possible to pass return values down the pipe, one could use a wrapper program to create some kind of fail-pipe system, where the output of a pipe is either the output of the last command that failed, or the last command if none failed.

TobiSGD 01-02-2013 07:31 PM

I don't really see why you want to use a pipe here. A pipe is used to pass output of a program to another program. If the return code is all you need there is no need for a pipe at all, just break up your pipe at the points where you need to get the return code to work with it.

hydraMax 01-02-2013 08:47 PM

Quote:

Originally Posted by TobiSGD (Post 4861691)
I don't really see why you want to use a pipe here. A pipe is used to pass output of a program to another program. If the return code is all you need there is no need for a pipe at all, just break up your pipe at the points where you need to get the return code to work with it.

I'm interested in both (standard) output and return value. It difficult to give any concrete example, because it is still nebulous in my own head. But basically what I'm interested in is a way to create a pipe, with real flowing data, that behaves differently depending on the return codes of commands in the pipe. One application might be a "failing" pipe with the following behavior: if all the commands in the pipe succeed, the final (standard) output of the pipe is the stdout of the last command. But if one of the commands fails, then the output of the whole pipe is the output of the last command that failed. Say, we have a wrapper command that makes this possible, called PF ("possibly fail")

PF parse "myfile" | PF refmtresults | PF updatedatabase | emailoutputto "admin@example.com"

Anyway, that is the sort of thing I'm thinking of. Maybe a "failing" pipe isn't really necessary, being as there is a division between stderr and stdout (not sure). But I imagine there might be other possible applications as well.

gnashley 01-03-2013 02:21 AM

PIPE_STATUS is what you want to look at.

NevemTeve 01-03-2013 03:59 AM

I have a similar question. Say I have a command like this:

Code:

make all 2>&1 | tee log.make.all
echo $?

The $? will be the return status of tee but it'd be better if it were that of make.

millgates 01-03-2013 05:36 AM

Actually, I think it's PIPESTATUS (without the underscore).

example:

Code:

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


NevemTeve 01-03-2013 05:53 AM

Wow, thank you!

hydraMax 01-04-2013 03:28 AM

Quote:

Originally Posted by gnashley (Post 4861851)
PIPE_STATUS is what you want to look at.

I think that PIPESTATUS does not work for what I wish to accomplish, because it suffers from the same issue as $?; i.e., it gives status information on the /last pipeline completed/, not the current pipeline. E.g.:

Code:

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

What I am looking for is a way to pass return values down a pipeline.

millgates 01-04-2013 07:10 AM

Quote:

Originally Posted by hydraMax (Post 4862681)
I think that PIPESTATUS does not work for what I wish to accomplish, because it suffers from the same issue as $?; i.e., it gives status information on the /last pipeline completed/, not the current pipeline.

No, it won't work for you. The piped commands are executed in subshells, so they can not be aware of each other's exit codes.

Quote:

Originally Posted by hydraMax
But if one of the commands fails, then the output of the whole pipe is the output of the last command that failed.

"Last command that failed"? What's that? The processes are not run one after another. They all run simultaneously. The fact that their stdin and stdout file descriptors are redirected in a certain way does not make one process depend on the others. The commands in a pipe are sent to subshells regardless of what they do. It's up to each of these subshells to handle executing of the command they were given. None of these subshells knows anything about any of the others. It just gets input from somewhere and writes output somewhere.

The subshell then exits and sends its exit status to the parent shell. Only after all of the subshells exit, the $? and $PIPESTATUS are set.
If you have something like

Code:

grep foo file | grep bar | grep baz
By the time grep bar returns non-zero exit status, it is already too late to decide you want to print its output on screen instead of the output of grep baz.

You could possibly just echo the status code

Code:

(foo && echo $?) | bar
but I don't think it would be very useful. If you think you need to know the exit status of a piped command on the other side of the pipe, your program is probably poorly designed.


All times are GMT -5. The time now is 12:39 PM.