bash
la version 4 a une coproc
commande qui permet de le faire en pur bash
sans les pipes nommées:
coproc cmd1
eval "exec cmd2 <&${COPROC[0]} >&${COPROC[1]}"
D'autres coquilles peuvent aussi faire coproc
aussi bien.
Vous trouverez ci-dessous une réponse plus détaillée, mais trois chaînes au lieu de deux, ce qui en fait un peu plus intéressant.
Si vous êtes heureux d'utiliser aussi cat
et stdbuf
puis construire peut être plus facile à comprendre.
Version utilisant bash
avec cat
et stdbuf
, facile à comprendre:
# 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}"
Notez que vous devez utiliser eval car le développement de variable dans <& $ var est illégal dans ma version de bash 4.2.25.
Version using pure bash
: divisez en deux parties, lancez le premier pipeline sous coproc, puis lancez la deuxième partie (une seule commande ou un pipeline) en la reconnectant à la première:
coproc {
cmd 1 | cmd2
}
endcmd="exec cmd3 <&${COPROC[0]} >&${COPROC[1]}"
eval "${endcmd}"
Preuve de concept:
fichier ./prog
, juste un programme factice à utiliser, baliser et réimprimer des lignes. Utiliser des sous-réservoirs pour éviter les problèmes de mise en mémoire tampon est peut-être excessif, ce n'est pas le problème.
#!/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
Ceci est une version utilisant bash
, cat
etstdbuf
#!/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 fichier ./start_part
. Ceci est une version utilisant pur bash
uniquement. Pour les besoins de la démonstration, je l’utilise encore stdbuf
car votre programme réel devra de toute façon gérer la mise en mémoire tampon en interne pour éviter le blocage en raison de la mise en mémoire tampon.
#!/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}"
Sortie:
> ~/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
Ça le fait.