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.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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
up vote 15 down vote accepted

If pipes on your system are bidirectional (as they are on Solaris 11 and 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:

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
One named pipe is sufficient: prog1 < fifo | prog2 > fifo. – Andrey Vihrov Nov 2 '12 at 16:47
@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
@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
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 '14 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 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 '14 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):

echo "foo" # change to 'bar' in second file

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

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

There is also dpipe, the "bi-directional pipe", included in vde2 package, and included in current distro package management systems.


dpipe processA = processB

share|improve this answer

A convenient building block for writing such bidirectional pipes is something that connects the stdout and stdin of the current process together. Let us call it ioloop. After calling this function, you only need to start a regular pipe:

ioloop &&     # stdout -> stdin 
cmd1 | cmd2   # stdin -> cmd1 -> cmd2 -> stdout (-> back to stdin)

If you do not want to modify the descriptors of the top-level shell, run this in a subshell:

( ioloop && cmd1 | cmd2 )

Here is a portable implementation of ioloop using a named pipe:

ioloop() {
    FIFO=$(mktemp -u /tmp/ioloop_$$_XXXXXX ) &&
    trap "rm -f $FIFO" EXIT &&
    mkfifo $FIFO &&
    ( : <$FIFO & ) &&    # avoid deadlock on opening pipe
    exec >$FIFO <$FIFO

The named pipe exists in the filesystem only briefly during ioloop setup. This function is not quite POSIX because mktemp is deprecated (and potentially vulnerable to a race attack).

A linux-specific implementation using /proc/ is possible that does not require a named pipe, but I think this one is more than good enough.

share|improve this answer

Your Answer


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.