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


16

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

./A | ./B

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



これはコマンドではなく、bashプロセスによって作成されたkenerlオブジェクトであり、プロセスAのstdoutおよびBとしてのstdinとして使用されます。2つのプロセスがほぼ同時に開始されます。
炸鱼薯条德里克

1
カーネルパイプラインのためにpipefsファイルシステム内のオブジェクトですが、限り、シェル自体に関しては- -技術的にパイプラインのコマンドだとあなたしている正しい炸鱼@
Sergiy Kolodyazhnyy

回答:


26

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

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

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

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

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

「消費者」と「プロデューサー」という言葉を使いたいなら、それも大丈夫だと思います。

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


2
DOSでは、複数のプロセスをサポートしていないため、一時ファイルへの書き込みが使用されていました。
CSM

2
@AlexVongただし、一時ファイルを使用した例は完全に同等ではないことに注意してください。プログラムはファイルの内容をシークすることを選択できますが、パイプからのデータはシークできません。より良い例はmkfifo、名前付きパイプを作成し、パイプからバックグラウンドでBを開始し、次にAに書き込むことです。ただし、効果は同じであるため、これは非常に簡単です。
クサラナナンダ

2
@AlexVongこの記事で行われた単純化により、実際のパイプラインから離されます。並列実行は真の意味であり、最適化ではありません。これは、シェルパイプラインを見た人に対するモナドの評価または構成について合理的な嘘つきの説明ですが、他の方向では無効です。Kusalanandaのfifoバージョンは近いですが、モデルのエラー伝播部分は非常に重要であり、複製できません。(これらはすべて、「シェルパイプラインは単なる関数合成」トレインに乗っている人として言う)
マイケルホーマー

6
@AlexVongいいえ、それは完全に軌道に乗っていません。それは次のような単純なことでさえ説明できません yes | sed 10q
ビリーおじさん

1
@UncleBillyあなたの例に同意します。これは、マイケルが指摘したように、並列実行が本当に必要であることを示しています。それ以外の場合は、終了しません。
アレックス

2

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

生産者-消費者部、パイプラインがので、そのパターンによって記述することができます。

  • プロデューサーとコンシューマーは固定サイズのバッファーを共有し、少なくともLinuxとMacOS Xでは、パイプラインバッファーのサイズ固定されています
  • プロデューサーとコンシューマーは疎結合であり、パイプラインのコマンドは互いの存在を知りません(積極的に/proc/<pid>/fdディレクトリをチェックしていない限り)。
  • 生産者はへの書き込みstdoutと消費者が読んでstdin、彼らが実行されている単一のコマンドであるかのように、別名彼らはお互いなしでは存在できます

ここで見た違いは、他の言語のProducer-Consumerとは異なり、シェルコマンドはバッファリングを使用し、バッファがいっぱいになるとstdoutを書き込みますが、Producer-Consumerがそのルールに従う必要があるという言及はありません。データ(パイプラインが行わない他の何か)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.