bashla versión 4 tiene un coproccomando que permite que esto se haga en puro bashsin canalizaciones con nombre:
coproc cmd1
eval "exec cmd2 <&${COPROC[0]} >&${COPROC[1]}"
Algunas otras conchas también pueden funcionar coproctambién.
A continuación se muestra una respuesta más detallada, pero encadena tres comandos, en lugar de dos, lo que hace que sea un poco más interesante.
Si está contento de usar también caty stdbufluego construir, puede ser más fácil de entender.
Versión bashcon caty stdbuffá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}"
Tenga en cuenta que debe usar eval porque la expansión variable en <& $ var es ilegal en mi versión de bash 4.2.25.
Versión usando pure bash: divídase en dos partes, inicie la primera tubería bajo coproc, luego almuerce la segunda parte, (ya sea un solo comando o una tubería) volviendo a conectarla a la primera:
coproc {
cmd 1 | cmd2
}
endcmd="exec cmd3 <&${COPROC[0]} >&${COPROC[1]}"
eval "${endcmd}"
Prueba de concepto:
archivo ./prog, solo un programa ficticio para consumir, etiquetar y volver a imprimir líneas. Usar subconjuntos para evitar problemas de almacenamiento en búfer puede ser excesivo, no es el punto aquí.
#!/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 es una versión que usa bash, catystdbuf
#!/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 archivo ./start_part. Esta es una versión que usa puro bashsolamente. Para fines de demostración, todavía estoy usando stdbufporque su programa real tendría que lidiar con el almacenamiento interno de todos modos para evitar el bloqueo debido al almacenamiento en búfer.
#!/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}"
Salida:
> ~/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
Eso lo hace.