Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Everyone knows how to make unidirectional pipe between two programs (bind stdout of first one and stdin of second one): first | second.

But how to make bidirectional pipe, i.e. cross-bind stdin and stdout of two programs? Is there easy way to do it in a shell?

share|improve this question
    
Short answer: no, you need two pipes. –  jordanm Nov 2 '12 at 14:44
    
OK, how to easy connect two programs via two pipes? –  Corvus Nov 2 '12 at 14:57
    
BTW: What are you trying to accomplish? There might be a better way. –  derobert Nov 2 '12 at 15:13

5 Answers 5

up vote 9 down vote accepted

If pipes on your system are bidirectional (as they are on some BSDs at least, but not Linux):

cmd1 <&1 | cmd2 >&0

Beware of deadlocks though.

Also note that some versions of ksh93 on some systems implement pipes (|) using a socket pair. socket pairs are bidirectional, but ksh93 explicitly shuts down the reverse direction, so the command above wouldn't work with those ksh93s even on systems where pipes (as created by the pipe(2) system call) are bidirectional.

share|improve this answer
    
does anyone know whether this works on linux too? (using archlinux here) –  heinrich5991 Nov 2 '12 at 17:43
    

Well, its fairly "easy" with named pipes (mkfifo). I put easy in quotes because unless the programs are designed for this, deadlock is likely.

mkfifo fifo0 fifo1
( prog1 > fifo0 < fifo1 ) &
( prog2 > fifo1 < fifo0 ) &
( exec 30<fifo0 31<fifo1 )      # write can't open until there is a reader
                                # and vice versa if we did it the other way

Now, there is normally buffering involved in writing stdout. So, for example, if both programs were:

#!/usr/bin/perl
use 5.010;
say 1;
print while (<>);

you'd expect a infinite loop. But instead, both would deadlock; you would need to add $| = 1 (or equivalent) to turn off output buffering. The deadlock is caused because both programs are waiting for something on stdin, but they're not seeing it because its sitting in the stdout buffer of the other program, and hasn't yet been written to the pipe.

share|improve this answer
15  
One named pipe is sufficient: prog1 < fifo | prog2 > fifo. –  Andrey Vihrov Nov 2 '12 at 16:47
2  
@AndreyVihrov that's true, you can substitute an anonymous pipe for one of the named ones. But I like the symmetry :-P –  derobert Nov 2 '12 at 17:26
    
@Andrey Vihrov: Perfect! But how can also I see communication of this programs in a terminal? I.e. I want, prog1 and prog2 also output to calling terminal. –  Corvus Nov 3 '12 at 9:18
2  
@user14284: On Linux, you can probably do it with something like prog1 < fifo | tee /dev/stderr | prog2 | tee /dev/stderr > fifo. –  Andrey Vihrov Nov 6 '12 at 10:28
1  
If you make it prog2 < fifo0 > fifo1, you can avoid your little dance with exec 30< ... (which by the way only works with bash or yash for fds over 10 like that). –  Stéphane Chazelas Apr 5 at 20:08

I am not sure if this is what you are trying to do:

nc -l -p 8096 -c second &
nc -c first 127.0.0.1 8096 &

This begins by opening a listening socket on port 8096, and once a connection is established, spawns program second with its stdin as the stream output and stdout as the stream input. This is

Then, a second nc is launched which connect to the listening port and spawn program first with its stdout as the stream input and its stdin as the stream output.

This is not exactly done using pipe, but it seams doing what you need.

As this uses the network, this can be done on 2 remote computes. This is almost the was a web server (second) and a web browser (first) work.

share|improve this answer

You can use pipexec:

$ pipexec -- [A cmd1 ] [B cmd2 ] '{A:1>B:0}' '{B:1>A:0}'
share|improve this answer
    
+1 Nice job in the README.md –  goldilocks Apr 5 at 14:25

There are many great answers here. So I just want to add something to easy play around with them. I assume stderr is not redirected anywhere. Create two scripts (let say a.sh and b.sh):

#!/bin/bash
echo "foo" # change to 'bar' in second file

for i in {1..10}; do
  read input
  echo ${input}
  echo ${i} ${0} got: ${input} >&2
done

Then when you connect them any good way you should see on the console:

1 ./a.sh got: bar
1 ./b.sh got: foo
2 ./a.sh got: foo
2 ./b.sh got: bar
3 ./a.sh got: bar
3 ./b.sh got: foo
4 ./a.sh got: foo
4 ./b.sh got: bar
...
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.