Итак, вы хотите направить вывод cmd1 и в cmd2, и в cmd3, и получить вывод cmd2 и cmd3 в разные переменные?
Тогда кажется, что вам нужно два канала из оболочки, один подключен к выходу cmd2 и один к выходу cmd3, и оболочка использует select()
/ poll()
для чтения из этих двух каналов.
bash
для этого не подойдет, вам понадобится более продвинутая оболочка, такая как zsh
. zsh
не имеет необработанного интерфейса для pipe()
, но если вы работаете в Linux, вы можете использовать тот факт, что /dev/fd/x
в обычном канале действует как именованный канал, и использовать подход, аналогичный тому, что использовался в Чтение/запись в тот же файловый дескриптор с перенаправлением оболочки
#! /bin/zsh -
cmd1() seq 20
cmd2() sed 's/1/<&>/g'
cmd3() tr 0-9 A-J
zmodload zsh/zselect
zmodload zsh/system
typeset -A done out
{
cmd1 > >(cmd2 >&3 3>&-) > >(cmd3 >&5 5>&-) 3>&- 5>&- &
exec 4< /dev/fd/3 6< /dev/fd/5 3>&- 5>&-
while ((! (done[4] && done[6]))) && zselect -A ready 4 6; do
for fd (${(k)ready[(R)*r*]}) {
sysread -i $fd && out[$fd]+=$REPLY || done[$fd]=1
}
done
} 3> >(:) 5> >(:)
printf '%s output: <%s>\n' cmd2 "$out[4]" cmd3 "$out[6]"
Если вы посмотрите на исходники ядра (здесь 5.4.48 ), вы сможете найти реализацию функций, которые обрабатывают чтение/запись в файловые дескрипторы eventfd:
// fs/eventfd.c
static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct eventfd_ctx *ctx = file->private_data;
...
spin_lock_irq(&ctx->wqh.lock);
static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count,
loff_t *ppos)
{
struct eventfd_ctx *ctx = file->private_data;
...
spin_lock_irq(&ctx->wqh.lock);
Реализация имеет внутреннюю блокировку, что делает ее потокобезопасной.