web-dev-qa-db-ja.com

Linuxではパイプはどのように機能しますか?

配管はどのように機能しますか? CLIを介してプログラムを実行し、出力をファイルにリダイレクトすると、そのファイルが書き込まれているときに、そのファイルを別のプログラムにパイプすることができますか?

基本的には、ファイルに1行が書き込まれると、すぐに2番目のアプリケーションにパイプ処理したい(既存のプログラムから動的にグラフを描こうとしている)。パイピングが次のコマンドに進む前に最初のコマンドを完了したかどうか不明です。

どんなフィードバックでも大歓迎です!

30
Jon

1つのプログラムの出力を別のプログラムの入力にリダイレクトする場合は、単純なパイプラインを使用します。

_program1 arg arg | program2 arg arg
_

_program1_の出力をファイルに保存し、パイプして_program2_にパイプしたい場合は、 tee(1)

_program1 arg arg | tee output-file | program2 arg arg
_

パイプライン内のすべてのプログラムは同時に実行されます。ほとんどのプログラムは通常blockingI/Oを使用します。入力を読み取ろうとして何もない場合、block:thatつまり、それらは停止し、オペレーティングシステムは、より多くの入力が利用可能になるまで(CPUの浪費を避けるため)実行をスケジュール解除します。同様に、パイプラインの前のプログラムが後のプログラムがデータを読み取るよりも速くデータを書き込んでいる場合、最終的にパイプのバッファーがいっぱいになり、ライターがブロックします。OSは、パイプのバッファーがリーダーによって空になるまでスケジュールを解除し、次に再び書き続けることができます。


[〜#〜]編集[〜#〜]

_program1_の出力をコマンドラインパラメーターとして使用する場合は、逆引用符または$()構文を使用できます。

_# Runs "program1 arg", and uses the output as the command-line arguments for
# program2
program2 `program1 arg`

# Same as above
program2 $(program1 arg)
_

$()構文はより明確であり、ネストできるため、推奨されます。

56
Adam Rosenfield

パイピング2番目のコマンドを実行する前に最初のコマンドを完了しません。 Unix(およびLinux)パイピングは、すべてのコマンドを同時に実行します。次の場合、コマンドは中断されます

  • 入力が不足しています。

  • それは後継者が消費する準備ができているよりもはるかに多くの出力を生成しています。

ほとんどのプログラムの場合、出力はbufferedです。これは、OSが大量の出力(おそらく8000文字程度)を蓄積してから次の出力に渡すことを意味しますパイプラインの段階。このバッファリングは、プロセスとカーネルの間でやり過ぎる切り替えを避けるために使用されます。

パイプラインの出力をすぐに送信したい場合は、unbufferedI/Oを使用できます。これは、Cではfflush()バッファリングされた出力がすぐに確実に次のプロセスに送信されるようにします。バッファリングされていない入力も可能ですが、入力が不足しているプロセスは通常、バッファがいっぱいになるのを待たずに、取得できるすべての入力を処理するため、通常は不要です。

一般的なアプリケーションでは、バッファなしの出力は推奨されません。通常は、デフォルトで最高のパフォーマンスが得られます。ただし、最初のプロセスで利用可能な情報をすぐに取得して動的グラフを作成したい場合は、バッファリングされていない出力を使用する必要があります。 Cを使用している場合は、出力を送信したいときにfflush(stdout)を呼び出すだけで十分です。

26
Norman Ramsey

プログラムがstdinおよびstdoutを使用して通信している場合は、作成後にfflush(stdout)を呼び出すか、標準のIOバッファリング。C/C++でパイプラインを最適に実装する方法を実際に説明していると考えることができる最良のリファレンスは NIX環境での高度なプログラミング または NIXネットワークプログラミング:ボリューム2この記事 から始めることもできます。

9
D.Shawley

2つのプログラムがファイルの読み取りと書き込みを要求し、stdin/stdoutを使用しない場合は、ファイルの代わりに名前付きパイプを使用できることがあります。

Mknod(1)コマンドで名前付きパイプを作成します。

$ mknod /tmp/named-pipe p

次に、/ tmp/named-pipeに読み書きするようにプログラムを構成します(適切と思われるパス/名前を使用してください)。

この場合、両方のプログラムが並行して実行され、他の回答で説明されているように、パイプが満杯または空になると、必要に応じてブロックされます。

3
camh