bash
la versione 4 ha un coproc
comando che consente di farlo in puro bash
senza named pipe:
coproc cmd1
eval "exec cmd2 <&${COPROC[0]} >&${COPROC[1]}"
Anche alcune altre shell possono fare coproc
altrettanto.
Di seguito è una risposta più dettagliata, ma concatena tre comandi, anziché due, il che rende solo un po 'più interessante.
Se sei felice di usare anche cat
e stdbuf
quindi costruire può essere reso più facile da capire.
Versione bash
con cat
e stdbuf
, facile da capire:
# 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}"
Nota, devi usare eval perché l'espansione variabile in <& $ var è illegale nel mio versio di bash 4.2.25.
Versione che utilizza pure bash
: suddividere in due parti, avviare la prima pipeline in coproc, quindi pranzare la seconda parte (un singolo comando o una pipeline) ricollegandola alla prima:
coproc {
cmd 1 | cmd2
}
endcmd="exec cmd3 <&${COPROC[0]} >&${COPROC[1]}"
eval "${endcmd}"
Verifica teorica:
file ./prog
, solo un programma fittizio per consumare, taggare e ristampare le linee. L'uso di subshells per evitare problemi di buffering può essere eccessivo, non è questo il punto.
#!/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
Questa è una versione che utilizza bash
, cat
estdbuf
#!/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}"
o file ./start_part
. Questa è una versione che utilizza bash
solo puro . Per scopi dimostrativi sto ancora usando stdbuf
perché il tuo vero prog dovrebbe occuparsi comunque del buffering internamente per evitare il blocco dovuto al 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}"
Produzione:
> ~/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
Questo lo fa.