First of all a small refresher on what piping is and how it works
when you do something like
echo 2 | cat
stdout of echo
is being piped to cat's stdin, cat writes again the result that was read from stdin to stdout and you see the result in your terminal, this is a example of unidirectional piping, bidirectional piping would be if cat could write back to echo and echo could read what was piped, basically you would have two program that can communicate with each other.
On Linux we do this creating a named pipe, which is just a special type of file using the FIFO(first in first out) method so one program can write to that file and the other can read and vice versa, the two easiest ways of creating a FIFO is using the program mkfifo, or using bash built-in function coproc, both do basically the same thing the only different is that when using coproc you end up with more elegant code depending on who you ask, let's create a simple program and implement bidirectional piping using mkfifo, which is more explicit, I'm gonna write one program in bash and the other one in javascript(node) but any language that can write to stdin, stderr and read from stdout would work(so basically all of them)
let's create three programs, prog1, prog2 and program to create the FIFO and call the other programs
prog1.sh
echo "bash: hello!"
read line
echo $line 1>&2
echo "bash: how are you doing?"
read line
echo $line 1>&2
prog2.js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
rl.on('line', function (cmd) {
if(cmd == 'bash: hello!') {
console.error(cmd);
console.log("javascript: hello!");
}
if(cmd == 'bash: how are you doing?') {
console.error(cmd);
console.log("javascript: I'm fine, thanks!");
}
});
and the program to create the FIFO and call the two other programs
start.sh
mkfifo p1 p2
bash ./prog1.sh > p1 < p2 &
node ./prog2.js < p1 > p2
rm -rf p1 p2
We delete the FIFOs in the last line to avoid a warning the next time we run bash start.sh
, the warning would just tell us that the FIFO already exist.
now we can run everything with
bash ./start.sh
It works!!! one program can send messages to the other program, when both programs end, start also ends, also we can only read or write to the FIFO if two program open the FIFO file, if you remove the last line of start.sh
you can see the FIFO files that were created in the same directory.
If you try to open the FIFO file in a text editor, your text editor will probably crash on hang indefinitely. you might think that the same thing is possible just creating regular files, but the code would be a lot more cumbersome, FIFO allows us to write pretty elegant code connecting two different programs, or two different instances of the same program, let's talk a little bit about the actual code
mkfifo p1 p2
This command creates two FIFO files called p1 and p2
bash ./prog1.sh > p1 < p2 &
here we run the first bash program and tell it to point it's stdout
to p1 and stdin
to p2
node ./prog2.js < p1 > p2
here we run the second program and do the opposite, we tell him to read from p1 and write to p2
rm -rf p1 p2
This line is not required it just avoids the warning when we run mkfifo
again the next time
Now let's have a look at the programs themselves, first the bash program
echo "bash: hello!"
read line
echo $line 1>&2
echo "bash: how are you doing?"
read line
echo $line 1>&2
The only think that might be confusing here if you don't know bash very well is the line
echo $line 1>&2
here we're redirecting from stdout
to stderr
if we don't do this we can't see the messages in our terminal, remember that the stdout is going to the other program and not to the terminal, if we just echoed without the redirecting the string will go to the FIFO and be read by prog2, same thing for the javascript code
console.error(cmd);
we do the above so we can print to stderr, the javascript program prints the bash messages and the bash program prints the javascript messages, another difference is that the javascript program calls the same callback every time it reads something from the fifo that's why we have the if statements to identify which message was receive and reply accordingly.
Top comments (0)