How about using shell's coproc feature for pure bash solution without temporary names pipes or such. Some other shells also can do coproc as well.
Edit: for 2 progs, initial answer and rest of examples for 3 progs
coproc cmd1 eval "exec cmd2 <&${COPROC[0]} >&${COPROC[1]}" If you are happy to also use cat and stdbuf then construct can be made easier to understand.
Version using bash with cat and stdbuf, easy to understand:
# start pipeline coproc { cmd1 | cmd2 | cmd3 } # create command to reconnect STDOUT `cmd3` to STDIN of `cmd1` endcmd="exec stdbuf -i0 -o0 /bin/cat <&${COPROC[0]} >&${COPROC[1]}" # eval the command. eval "${endcmd}" Note, have to use eval because variable expansion in <&$var is illegal in my versio of bash 4.2.25.
Version using pure bash: Break up into two parts, launch first pipeline under coproc, then lunch second part, (either a single command or a pipeline) reconnecting it to the first:
coproc { cmd 1 | cmd2 } endcmd="exec cmd3 <&${COPROC[0]} >&${COPROC[1]}" eval "${endcmd}" Proof of concept:
file ./prog, just a dummy prog to consume, tag and re-print lines. Using subshells to avoid buffering problems maybe overkill, it's not the point here.
#!/bin/bash let c=0 sleep 2 [ "$1" == "1" ] && ( echo start ) while : ; do line=$( head -1 ) echo "$1:${c} ${line}" 1>&2 sleep 2 ( echo "$1:${c} ${line}" ) let c++ [ $c -eq 3 ] && exit done file ./start_cat This is a version using bash, cat and stdbuf
#!/bin/bash echo starting first cmd>&2 coproc { stdbuf -i0 -o0 ./prog 1 \ | stdbuf -i0 -o0 ./prog 2 \ | stdbuf -i0 -o0 ./prog 3 } echo "Delaying remainer" 1>&2 sleep 5 cmd="exec stdbuf -i0 -o0 /bin/cat <&${COPROC[0]} >&${COPROC[1]}" echo "Running: ${cmd}" >&2 eval "${cmd}" or file ./start_part. This is a version using pure bash only. For demo purposes I am still using stdbuf because your real prog would have to deal with buffering internally anyway to avoid blocking due to buffering.
#!/bin/bash echo starting first cmd>&2 coproc { stdbuf -i0 -o0 ./prog 1 \ | stdbuf -i0 -o0 ./prog 2 } echo "Delaying remainer" 1>&2 sleep 5 cmd="exec stdbuf -i0 -o0 ./prog 3 <&${COPROC[0]} >&${COPROC[1]}" echo "Running: ${cmd}" >&2 eval "${cmd}" Output:
> ~/iolooptest$ ./start_part starting first cmd Delaying remainer 2:0 start Running: exec stdbuf -i0 -o0 ./prog 3 <&63 >&60 3:0 2:0 start 1:0 3:0 2:0 start 2:1 1:0 3:0 2:0 start 3:1 2:1 1:0 3:0 2:0 start 1:1 3:1 2:1 1:0 3:0 2:0 start 2:2 1:1 3:1 2:1 1:0 3:0 2:0 start 3:2 2:2 1:1 3:1 2:1 1:0 3:0 2:0 start 1:2 3:2 2:2 1:1 3:1 2:1 1:0 3:0 2:0 start That does it.