bash
la versión 4 tiene un coproc
comando que permite que esto se haga en puro bash
sin canalizaciones con nombre:
coproc cmd1
eval "exec cmd2 <&${COPROC[0]} >&${COPROC[1]}"
Algunas otras conchas también pueden funcionar coproc
tambié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 cat
y stdbuf
luego construir, puede ser más fácil de entender.
Versión bash
con cat
y 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}"
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
, cat
ystdbuf
#!/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 bash
solamente. Para fines de demostración, todavía estoy usando stdbuf
porque 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.