bashla versione 4 ha un coproccomando che consente di farlo in puro bashsenza named pipe:
coproc cmd1
eval "exec cmd2 <&${COPROC[0]} >&${COPROC[1]}"
Anche alcune altre shell possono fare coprocaltrettanto.
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 cate stdbufquindi costruire può essere reso più facile da capire.
Versione bashcon cate 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, catestdbuf
#!/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 bashsolo puro . Per scopi dimostrativi sto ancora usando stdbufperché 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.