Aardbei
Aardbei

Reputation: 361

What is the cleanest way to create a non-linear pipeline?

What is the cleanest (simplest, most efficient, shortest, quickest, easiest, most elegant) way to create a non-linear pipeline like this in Bash?

I have three commands: mksock, irclogin, and ircpingpong. I want to pipe stdin, irclogin, and ircpingpong into mksock, and pipe mksock into stdout and ircpingpong. This means that mksock and ircpingpong are in a loop. I drew a diagram:

Diagram

irclogin only needs to be run once and be the first input into mksock. After that, ircpingpong, and stdin should be accepted at any time. I am currently using pipes and a temporary file like this:

#!/bin/bash

server=127.0.0.1
port=6667

infifo=/tmp/ircin
outfifo=/tmp/ircout
pongfifo=/tmp/ircpong

rm $infifo
rm $outfifo
rm $pongfifo
mkfifo $infifo
mkfifo $outfifo
touch $pongfifo

( irclogin | cat - $infifo & tail -f $pongfifo; ) | mksock $server $port | tee $outfifo | stdbuf -oL ircpingpong > $pongfifo &
cat < $outfifo &
cat > $infifo
pkill tail

This works, but I want to know if there is a better way to do this. It bothers me that I am using a file rather than a pipe for looping back from ircpingpong to mksock using tail. Using a pipe didn't work because, to my understanding, something is written to the pipe before tail -f starts reading from it, and so it misses it.

It also bothers me that I have to kill tail at the end of the script, because it doesn't stop on it's own and would leave the socket connected even after the script has ended.

Upvotes: 13

Views: 484

Answers (2)

Hln
Hln

Reputation: 767

I can suggest a version without temporary files, and with two fifo-s:

fifo1=/tmp/fifo1
fifo2=/tmp/fifo2
rm $fifo1
rm $fifo2
mkfifo $fifo1
mkfifo $fifo2

ircpingpong < $fifo2 > $fifo1 &
(mksock <$fifo1|tee $fifo2 )&
irclogin >$fifo1 &
cat >$fifo1

The idea is to run all programs separately, and only ensure that input and output of each program is redirected properly according to this diagram:

pipe-flow

Of course, ircpingpong must read stdin and write to stdout, irclogin must write to stdout, and mksock must read from stdin and write to stdout.

Upvotes: 4

Don Hatch
Don Hatch

Reputation: 5509

Here's something that uses just one fifo.

fifo=/tmp/myfifo
rm $fifo
mkfifo $fifo

((ircpingpong < $fifo &) && irclogin && cat) | mksock | tee $fifo

Add stdbuf as needed.

I don't know whether you will get your "something doesn't die on its own" problem; when I ctrl-c'ed the script, everything seemed to die.

Upvotes: 0

Related Questions