Two-way pipe in bash?

I have a binary who’s stdout is being redirected to the stdin of a python script, and I was wondering if there’s any way to send the stdout of the python script to the stdin of the binary, to get an effect something like this, (excuse my terrible ascii diagram):


 |->-binary -- python -->-|
/|                      |/
 |-<---<---<---<---<---<--|

My current bash code is just binary | python3 pythonscript.py.

Thanks!

Asked By: SpaghettiMan

||

You should be able to use named pipes to achieve what you want. You would redirect both input and output from each process to/from the other process.

binary < npipe1 > npipe2
python3 pythonscript.py < npipe2 > npipe1

The named pipes would have already been setup with:

mkfifo /dev/shm/npipe1
mkfifo /dev/shm/npipe2

Where the named pipes are being put to the shared memory directory, but that location is not mandatory.

Here is a simple example using bash and dash scripting:

doug@s19:~/temp$ cat test-fifo-job-control
#! /bin/dash
#
# test-fifo-job-control Smythies 2023.09.03
#       A simple example of using named pipes.
#       See https://askubuntu.com/questions/1484568/two-way-pipe-in-bash
#

# If they do not already exist, then create the named pipes.
# Note: sometimes they might need to be deleted and recreated.
#       i.e. if garbage was left in one, or both.

if [ ! -p /dev/shm/npipe1 ]
then
   mkfifo /dev/shm/npipe1
fi
if [ ! -p /dev/shm/npipe2 ]
then
   mkfifo /dev/shm/npipe2
fi

# Launch the first task
./test-fifo-part-1 < /dev/shm/npipe1 > /dev/shm/npipe2 &
#
# and supply the first input
echo 1000 >> /dev/shm/npipe1
#
# Now launch the second task
#./test-fifo-part-2 < /dev/shm/npipe2 > /dev/shm/npipe1
./test-fifo-part-2 < /dev/shm/npipe2 | tee /dev/shm/npipe1

#
# It'll go until stopped via ^C.

And:

doug@s19:~/temp$ cat test-fifo-part-1
#!/bin/bash

while :
  do
# Note: No error checking
  read next_number
  echo "$next_number"
# Slow things down.
  sleep 1
done

And:

doug@s19:~/temp$ cat test-fifo-part-2
#!/bin/bash

while :
  do
# Note: No error checking
  read next_number
  next_number=$((next_number+1))
  echo "$next_number"
# Slow things down.
  sleep 1
done

Example session:

doug@s19:~/temp$ ./test-fifo-job-control
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
^C
doug@s19:~/temp$

For the additional question in the comments:

If I’m piping using the bash script, and not something in the python
code, is there still a way I can print to stdout without it going to
the pipe?

Not with the simple example I gave. Note that I usually use this stuff with c programs and write output directly to the named pipes, thus leaving stdout available for other output.

Answered By: Doug Smythies
Categories: Answers Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.