bash
a versão 4 possui um coproc
comando que permite que isso seja feito de forma pura, bash
sem pipes nomeados:
coproc cmd1
eval "exec cmd2 <&${COPROC[0]} >&${COPROC[1]}"
Algumas outras conchas também podem funcionar coproc
.
Abaixo está uma resposta mais detalhada, mas encadeia três comandos, em vez de dois, o que torna um pouco mais interessante.
Se você estiver feliz em usar cat
e stdbuf
construir, pode ser mais fácil de entender.
Versão usando bash
com cat
e stdbuf
fácil de entender:
# 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}"
Observe que é necessário usar eval porque a expansão variável em <& $ var é ilegal no meu versio do bash 4.2.25.
Versão usando pure bash
: Divida em duas partes, inicie o primeiro pipeline sob coproc e depois alimente a segunda parte ((um único comando ou um pipeline) reconectando-o à primeira:
coproc {
cmd 1 | cmd2
}
endcmd="exec cmd3 <&${COPROC[0]} >&${COPROC[1]}"
eval "${endcmd}"
Prova de conceito:
arquivo ./prog
, apenas um programa fictício para consumir, marcar e reimprimir linhas. Usar sub-conchas para evitar problemas de buffer talvez exagere, não é o ponto aqui.
#!/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
Esta é uma versão usando 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}"
ou arquivo ./start_part
. Esta é uma versão usando bash
apenas puro . Para fins de demonstração, ainda estou usando, stdbuf
porque seu programa real precisaria lidar com o buffer internamente de qualquer maneira, para evitar o bloqueio devido ao buffer.
#!/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}"
Resultado:
> ~/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
Isso faz.