2つのコマンドを名前付きパイプに転送するときのレース

2つのコマンドを名前付きパイプに転送するときのレース

複数のソースからデータを受け取る名前付きパイプからデータを読み取るプロセスが必要です。

$ mkfifo /tmp/p

しかし、継続的に動作させる方法を知りません。

最初のシナリオ - 動作します

ターミナル1:

私のfifoに書き込むために2つのプロセスを設定します。

$ echo 'first' > /tmp/p; echo 'second' > /tmp/p

ターミナル2:

パイプから読む:

$ cat /tmp/p
first
second

上記の操作を逆の順序で実行しても動作します。

私の問題は、パイプで2つの別々のコマンドを実行しようとしたときに発生します。

2番目のケース - 機能しない

First.sh

#!/bin/sh
echo 'first' > /tmp/p

2番目.sh

#!/bin/sh
echo 'second' > /tmp/p

ターミナル1

$ sh first.sh; sh second.sh

ターミナル2

$ cat /tmp/p
first

最初の tty の実行は、sh second.sh名前付きパイプから別の項目を読み取るまで無期限にブロックされます。

私の考えでは何が起こっていると思いますか?

~からhttp://linux.die.net/man/7/pipe:

パイプの書き込みの終わりを参照するすべてのファイル記述子が閉じられている場合、パイプがread(2)を試みるとファイルの終わりが表示されます(read(2)は0を返します)。

したがって、echo終了すると、first.shそれを実行するシェルはファイル記述子を閉じます。これは、2番目のTTYにEOFが表示されることを意味します/tmp/pcat

シェルを使用してこの問題をどのように解決できますか?サブシェルが終了したときにパイプが閉じられないように、デフォルトの制御スクリプトで名前付きパイプの読み取り端への参照を保持する方法はありますか?実際、私は名前付きパイプのパスをサブシェルに渡します。私のサブシェルを独自の標準出力に出力してリダイレクトする必要がありますか?

ここに何か抜けたような感じがします。この例を除いて、名前付きパイプを使用することは、私が試したすべての操作で簡単でした。

ベストアンサー1

ただしないでください。

{ echo foo; echo bar;} > /tmp/p

制御スクリプトがパイプを開いたままにするには、次のようにします。

exec 3<> /tmp/p

読み書きモードで名前付きパイプを開くことは、パイプがまだ開いていない間にブロックを防ぐことです。まだインスタンスがない場合はインスタンス化します。少なくともLinuxでは動作しますが、POSIXでは動作を保証しません。

または(そして移植可能):

: < /tmp/p & exec 3> /tmp/p

その後、各プロセスに名前付きパイプを開くようにする代わりに、次のこともできます。

cmd >&3

最後に、次の操作を行います。

exec 3>&-

読者にそれが完了したことを知らせるために文を終えます。

反対のロジックが必要な場合は、すべてのsをs<に、sをsに変更してください。><>

おすすめ記事