web-dev-qa-db-ja.com

Unix / Linuxのパイプコマンドについて

私は2つの単純なプログラムを持っています:ABAが最初に実行され、次にBAの「stdout」を取得して、その「stdin」として使用します。私がGNU/Linuxオペレーティングシステムを使用していて、これを行う最も簡単な方法は次のようになると仮定します。

./A | ./B

このコマンドについて説明する必要がある場合、それはプロデューサー(A)から入力(つまり、読み取り)を受け取り、コンシューマー(B)に書き込むコマンドであると言えます。それは正しい説明ですか?何か不足していますか?

16
nihulus

間違ったとして目立つ質問についての唯一のことは、あなたが言うことです

Aが最初に実行され、次にBがAの標準出力を取得します。

実際、どちらのプログラムもほぼ同時に開始されます。 Bへの入力がない場合、読み取ろうとすると、読み取る入力があるまでブロックされます。同様に、Aから出力を読み取る人がいない場合、その書き込みは、出力が読み取られるまでブロックされます(一部はパイプによってバッファーされます)。

パイプラインに参加するプロセスを同期する唯一のものは、I/O、つまりパイプを介した読み取りと書き込みです。書き込みまたは読み取りが発生しない場合、2つのプロセスは互いに完全に独立して実行されます。一方が他方の読み取りまたは書き込みを無視した場合、無視されたプロセスはブロックされ、最終的にSIGPIPE信号(書き込みの場合)によって強制終了されるか、その標準入力ストリームでファイル終了条件が取得されます(読み取りの場合) )他のプロセスが終了したとき。

A | Bを記述する慣用的な方法は、2つのプログラムを含むパイプラインであるということです。最初のプログラムからの標準出力で生成された出力は、2番目のプログラムによって標準入力で読み取ることができます( "[の出力] Aは、[入力の] Bにパイプされます" )。シェルは、これを可能にするために必要な配管を行います。

「コンシューマー」と「プロデューサー」という言葉を使いたいのであれば、それも問題ないと思います。

これらがCで書かれたプログラムであることは関係ありません。これがLinux、macOS、OpenBSD、AIXであるという事実は関係ありません。

27
Kusalananda

ドキュメントで通常使用される用語は、1つ以上のコマンドで構成される「パイプライン」です POSIX定義を参照してください つまり、技術的に言えば、2つのコマンド、つまりシェルの2つのサブプロセスです。 (fork()+exec() 'ed外部コマンドまたはサブシェル)

producer-consumer 部分に関しては、パイプラインはそのパターンで記述できます。

  • プロデューサーとコンシューマーは固定サイズのバッファーを共有し、少なくともLinuxおよびMacOS Xでは、パイプラインバッファーの固定サイズ があります
  • プロデューサーとコンシューマーは疎結合であり、パイプライン内のコマンドはお互いの存在を認識しません(それらがアクティブに/proc/<pid>/fdディレクトリをチェックしている場合を除く)。
  • プロデューサーはstdoutに書き込み、コンシューマーはstdinを単一のコマンドが実行されているかのように読み取り、別名 はお互いに存在しなくても存在できます

ここで私が見る違いは、他の言語のProducer-Consumerとは異なり、シェルコマンドはバッファリングを使用し、バッファーがいっぱいになるとstdoutを書き込むということですが、Producer-Consumerはそのルールに従う必要があるという言及はありません-キューがいっぱいになるか破棄されるときだけ待つデータ(これはパイプラインが実行しない他のものです)。

2