how to redirect stdout of 2nd process back to stdi

2019-01-13 16:49发布

问题:

I have two processes which I need to connect like this:

proc1 -- sends output to proc2 proc2 -- sends output to proc1

So far, all pipe examples are of this kind: proc1 | proc2

That's nice, but how do I make the output of proc2 go to proc1?

A bash example would be nice. A Windows shell example would be great :)

Thanks in advance, Adrian.

Adding more details:

The system is expected to work as client-server system in which the client works with the server in a request-response interaction model. The interaction ends when the client has no more requests.

Interaction example: client: request1; server: response1; client: request2; server: response2; . . . . client: closeRequest; server: closeApproved;

At this point the server exits following a client exit. End of example.

It seems that a solution like (assuming pipe is available) client < pipe | server > pipe would not work (please correct me) because in this arrangement the client produces one big request, the shell pipes this big request to the server, then the server produces one big response, and finally the shell pipes this big response to the client.

回答1:

It looks like a bash coprocess may be what you want. Look up the coproc reserved word in the bash manual.


(Edit: adding simple usage scheme)

It works like this:

# start first process as a coprocess to the current shell
coproc proc1

# now ${COPROC[0]} contains the number of an open (input) file descriptor
# connected to the output of proc1, and ${COPROC[1]} the number of an
# open (output) file descriptor connected to the input of proc1.


# start second process, connecting its input- and outputstreams
# to the output- and inputstreams of the first process
proc2 <&${COPROC[0]} >&${COPROC[1]}

# wait on the first process to finish.
wait $COPROC_PID

If you may have multiple coprocesses, give your process a name like this:

coproc NAME {
    proc1
}

Then you can use NAME wherever COPROC was used before.


Here is a complete example program using a ping function as proc1 and proc2:

#!/bin/bash
#
# Example program using a bash coprocess to run two processes
# with their input/output streams 
#


#
# A function which reads lines of input and
# writes them back to standard output with the
# first char cut off, waiting 5s inbetween.
#
# It finishes whenever an empty line is read or written,
# or at end-of-file.
#
# The parameter $1 is used in debugging output on stderr.
#
function ping ()
{
    while read 
    do
        local sending
        echo "ping $1: received '$REPLY'" >&2
        [[ -n $REPLY ]] || break
        sleep 5s
        sending=${REPLY:1}
        echo "ping $1: sending '$sending'"  >&2
        echo $sending
        [[ -n $sending ]] || break
    done
    echo "ping $1: end" >&2
}

#
# Start first ping process as a coprocess with name 'p1'.
#

coproc p1 {
    ping 1
}

# send some initial data to p1. (Not needed if one of the processes
# starts writing before first reading.)
echo "Hello World" >&${p1[1]}
sleep 2.5s

#
# Run second ping process, connecting its default input/output
# to the default output/input of p1.
# 
ping 2 <&${p1[0]} >&${p1[1]}

# wait for the coprocess to finish too.
wait $p1_PID

It uses two invocations of a shell function instead of external programs, but it would work with such programs too. Here is the output (on stderr):

ping 1: received 'Hello World'
ping 1: sending 'ello World'
ping 2: received 'ello World'
ping 2: sending 'llo World'
ping 1: received 'llo World'
ping 1: sending 'lo World'
ping 2: received 'lo World'
ping 2: sending 'o World'
ping 1: received 'o World'
ping 1: sending ' World'
ping 2: received 'World'
ping 2: sending 'orld'
ping 1: received 'orld'
ping 1: sending 'rld'
ping 2: received 'rld'
ping 2: sending 'ld'
ping 1: received 'ld'
ping 1: sending 'd'
ping 2: received 'd'
ping 2: sending ''
ping 2: end
ping 1: received ''
ping 1: end


回答2:

here is a bash example using echo to provide some initial input and a named pipe to allow for the feedback loop:

mkfifo fifo
echo "fifo forever" | cat - fifo | tee fifo
  • proc1 (cat) takes input from stdin and fifo
  • proc2 (tee) passes output to stdout and fifo


回答3:

This is an example showing what you want, with two processes that both take one argument:

mkfifo fifo
./process1 argument1 < fifo | ./process2 argument1 > fifo

First we create a named pipe called fifo in the current directory. Then we execute process1 with fifo as input, whose output will go through the anonymous pipe | to the input of process2, whose output will go to fifo, closing the loop.

After exiting both processes you should delete the pipe, just the same way you delete a regular file:

rm fifo


回答4:

#!/bin/bash

fifo=$(/bin/mktemp -u)
/usr/bin/mkfifo $fifo

# register resources cleanup trap
trap "/bin/unlink $fifo" INT TERM EXIT

# start a background shell redirecting its output to the pipe
(for ((i=0; i < 5; ++i)); do echo "pam pam, i = $i"; sleep 1; done ) 1> $fifo&

# read the output of the background shell from the pipe
while read line 0< $fifo; do
  echo "param $line"
done

# wait for child process to terminate
wait


回答5:

Most shells make this hard to do, for good reason - it's very easy to get your programs deadlocked, where each is waiting for input from the other. Can you tell us more about what information you're trying to pass around? If you are just trying to make an RPC-like system, you should probably use a library that's designed for that.



标签: bash shell pipe