bash
версія 4 має coproc
команду, яка дозволяє це робити в чистому режимі bash
без названих труб:
coproc cmd1
eval "exec cmd2 <&${COPROC[0]} >&${COPROC[1]}"
Також можуть зробити coproc
це і інші снаряди .
Нижче більш детальна відповідь, але ланцюжок складається з трьох команд, а не двох, що робить лише трохи більш цікавим.
Якщо ви із задоволенням також використовуєте, cat
а stdbuf
потім конструкцію можна зробити простішою для розуміння.
Версія використання bash
з cat
і stdbuf
, легко зрозуміти:
# 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}"
Зауважте, доведеться використовувати eval, тому що розширення змінної в <& $ var є незаконним у моїй версії bash 4.2.25.
Версія з використанням чистого bash
: Розбийте на дві частини, запустіть перший конвеєр під копроком, потім другу частину обіду (або одну команду, або конвеєр), підключивши його до першої:
coproc {
cmd 1 | cmd2
}
endcmd="exec cmd3 <&${COPROC[0]} >&${COPROC[1]}"
eval "${endcmd}"
Доказ концепції:
файл ./prog
, просто фіктивна прога для споживання, тегів та повторного друку рядків. Використання допоміжних оболонок для уникнення проблем із буферизацією, можливо, надмірного рівня, тут справа не в цьому.
#!/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
файл ./start_cat
Це версія з використанням bash
, cat
іstdbuf
#!/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}"
або файл ./start_part
. Це версія, що використовує bash
лише чистий . Для демонстраційних цілей я все ще використовую, stdbuf
тому що ваша реальна прога так чи інакше повинна мати справу з буферизацією, щоб уникнути блокування через буферизацію.
#!/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}"
Вихід:
> ~/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
Це робить це.