I have a program which reads from and writes to file descriptor 3
. I want to let it write to fd 3
, and be able to write to the other end of the pipe interactively which the program should read over the same fd. I can create a pipe with mkfifo
(mkfifo /tmp/my_pipe
) and remap one end of it to fd 3
(./prog &3>/tmp/my_pipe
). I keep the pipe open using cat /tmp/my_pipe
. However, when the process tries to read from fd 3
, it receives a SIGTTIN
. Is it possible to launch the program as I intend from bash?

- 626
-
1https://unix.stackexchange.com/questions/53641/how-to-make-bidirectional-pipe-between-two-programs – ozzy Jan 08 '19 at 22:03
1 Answers
On (at least) Linux-based systems a FIFO or Named Pipe is unidirectional. In your situation you want to have a program reading and writing to the same FIFO. This gets even more tricky because you may well up with a deadlock if you exceed the pipe's internal buffer.
Two general points.
You cannot usefully have two readers; if you do, you'll find that your reads will interleave nondeterministically and your data will be shared between the two readers. You will not get the same data duplicated to both readers.
You can have two (or more) writers, but once again your output data will be interleaved in the order that it is received by the pipe. Unless your writers are carefully synchronised, data such as
First writer
andSecond writer
could end up being received as the garbledFirSecond wrstwrititerer
.
Using the program at the bottom of this answer, consider running the following two scenarios from different terminal sessions. Then try your own variations.
First terminal Second terminal Third terminal
-------------------- -------------------- --------------------
./fifo.sh read ./fifo.sh read ./fifo.sh write /etc/hosts
First terminal Second terminal Third terminal
-------------------- -------------------- --------------------
./fifo.sh write /etc/passwd ps -ef | ./fifo.sh write ./fifo.sh read
First terminal Second terminal Third terminal
-------------------- -------------------- --------------------
./fifo.sh both /etc/passwd
Script for fifo.sh
as follows
#!/bin/bash
#
pipe=/tmp/mypipe
########################################################################
# Reader
#
doRead()
{
echo "Reading from pipe $pipe" >&2
nl <"$pipe"
}
########################################################################
# Writer. We pause after every line (for effect)
#
doWrite()
{
[[ $# -eq 0 ]] && set -- -
echo "Writing to pipe $pipe" >&2
cat "$@" | while IFS= read -r line; do printf "%s\n" "$line"; sleep 1; done >>"$pipe"
}
########################################################################
# Reader-Writer. We pause after every line (for effect)
#
doBoth()
{
[[ $# -eq 0 ]] && set -- -
echo "Reading and writing to pipe $pipe" >&2
exec 3<>"$pipe"
nl <&3 & readPID=$!
cat "$@" | while IFS= read -r line; do printf "%s\n" "$line"; sleep 1; done >&3
kill $readPID 2>/dev/null
}
########################################################################
#
action="$1"
shift
if [[ ! -p "$pipe" ]]
then
echo "Creating pipe $pipe" >&2
mkfifo "$pipe"
fi
case "$action" in
read*) doRead "$@" ;;
write*) doWrite "$@" ;;
both) doBoth "$@" ;;
esac

- 116,213
- 16
- 160
- 287