web-dev-qa-db-ja.com

複数のプロセス間の通信

私は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
13
Aljaz

あなたが達成しようとしていることの用語は multiplexing です。

これは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は、単にSTDINから読み取り、そのIDと行をSTDOUTに書き込むbash関数です。 _$BASHPID_はサブシェルに対して更新されないため、_$$_ではなく_$$_を使用します(これは、managerの起動に使用するものです)。

fdsは、生成されたさまざまなmanagersのSTDINパイプを指すファイル記述子を保持する配列です。
次に、ループして5つのマネージャープロセスを作成します。 for (( ))構文を使用する方法は、よりわかりやすくするために、以前の方法ではありません。これはbash固有ですが、このスクリプトが行うことのいくつかはbash固有であるため、すべての方法でうまくいくかもしれません。

次に、exec {fd}> >(manager $i)に進みます。これはさらにいくつかのbash固有のことを行います。
最初のものは_{fd}>_です。これは、番号10以降の次の使用可能なファイル記述子を取得し、パイプの書き込み側をそのファイル記述子に割り当ててパイプを開き、ファイル記述子番号を変数_$fd_に割り当てます。

>(manager $i)は_manager $i_を起動し、基本的に>(manager $i)をそのプロセスのSTDINへのパスに置き換えます。したがって、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を入力したところ。

26
Patrick

teeおよびbash

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

マネージャーの数を構成可能にする必要がある場合、または異なるマネージャーからの出力が混合されないようにする場合:

export -f manager
cat foo | parallel --pipe --tee manager ::: {1..10}
0
Ole Tange