多个流程之间的沟通


13

我有一个bash脚本,该脚本将manager()函数作为x时间的单独进程运行。如何从脚本内部将消息转发到所有manager()进程?

我已经读过有关匿名管道的信息,但是我不知道如何与它共享消息。.我尝试使用命名管道进行操作,但是看来我必须为每个进程创建一个单独的命名管道吗?

最优雅的方法是什么?

到目前为止,这是我的代码:

#!/bin/bash

manager () {
    while :
    do
        echo "read what has been passed to \$line"
    done
}

x=1
while [ $x -le 5 ]
do
  manager x &
  x=$(( $x + 1 ))
done


while :
do
while read line
do
  echo "What has been passed through the pipe is ${line}"
  # should pass $line to every manager process

done < $1
done

exit 0

Answers:


25

您要完成的工作是多路复用

在bash中可以很容易地做到这一点,但是它确实需要一些更高级的bash功能。

我根据您的想法创建了一个脚本,我认为它可以完成您要完成的任务。我会在下面解释。

#!/bin/bash
manager() {
  while IFS= read -r line; do
    echo "manager[$1:$BASHPID]: $line"
  done
}

fds=()
for (( i=0; i<5; i++ )); do
  exec {fd}> >(manager $i)
  fds+=( $fd )
done

while IFS= read -r line; do
  echo "master: $line"
  for fd in "${fds[@]}"; do
    printf -- '%s\n' "$line" >&$fd
  done
done

manager是一个bash函数,它简单地从STDIN读取并将其标识符和行写入STDOUT。我们用$BASHPID,而不是$$作为$$没有得到亚壳层更新(这是我们将使用来启动manager

fds是一个数组,其中包含指向manager产生的各种s 的STDIN管道的文件描述符。
然后,我们遍历并创建5个管理器流程。我使用for (( ))语法而不是您做的方式,因为它更干净。这是特定于bash的,但是此脚本所做的一些操作都是特定于bash的,因此不妨一直进行下去。
 

接下来我们去exec {fd}> >(manager $i)。这还会执行一些bash特定的操作。
首先是{fd}>。这将在编号10或之后获取下一个可用的文件描述符,打开一个管道,并在管道的写侧分配该文件描述符,然后将文件描述符号分配给变量$fd

>(manager $i)启动manager $i和基本替代>(manager $i)与该进程的标准输入的路径。因此,如果manager以PID 1234的形式启动,则>(manager $i)可能会替换为/proc/1234/fd/0(这取决于OS)。

因此,假设下一个可用文件描述符号为10,并且使用PID 1234启动管理器,该命令exec {fd}> >(manager $i)基本上变为exec 10>/proc/1234/fd/0,并且bash现在具有指向该管理器的STDIN的文件描述符。
然后,由于bash将文件描述符号放入中$fd,我们将该描述符添加到数组中fds以备后用。
 

其余的都非常简单。主机从STDIN读取一行,遍历中的所有文件描述符$fds,并将该行发送到该文件描述符(printf ... >&$fd)。

 

结果看起来像这样:

$ /tmp/test.sh
hello
master: hello
manager[0:8876]: hello
manager[1:8877]: hello
manager[4:8880]: hello
manager[2:8878]: hello
manager[3:8879]: hello
world
master: world
manager[0:8876]: world
manager[1:8877]: world
manager[3:8879]: world
manager[2:8878]: world
manager[4:8880]: world

我在哪里输入helloworld


@Patrick the is works,但您遇到错字{fd},应该是$ {fd}
c4f4t0r

3
@ c4f4t0r这不是打字错误
Patrick

@Patrick在Suse 11上“ bash type.bash type.bash:第10行:exec:{fd}:找不到”我改为exec $ {fd},它像那样工作
c4f4t0r

2
@ c4f4t0r开放suse 11中的bash版本非常古老(3.2)。此功能在bash 4.0中实现。
帕特里克

感谢您提供许多有用的信息!一条小提琴:我能理解您为什么要说echo -- "$line"printf "%s\n" "$line"–但是--当下一个参数是硬编码的(而不是以开头-)时,为什么还要使用?
斯科特

0

teebash

cat foo | tee >(manager) >(manager) >(manager) >(manager) >(manager) >/dev/null

如果管理器的数量应该是可配置的,或者您希望不要混用来自不同管理器的输出:

export -f manager
cat foo | parallel --pipe --tee manager ::: {1..10}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.