パイプ
読み:パイプ
外語:pipe
あるタスク(またはプロセスやスレッド、以下同)の出力と、別のタスクの入力を接続する機能。
概要
例えば、あるタスクの標準出力を、別のタスクの標準入力に振り向ける機能である。
ある処理対象を、次々と異なるプログラムで処理していくような場合、この方法がよく用いられている。
% cat infile | sort | more
上の例は、ファイルinfileの内容を出力し、それをソートし、最後にmoreで表示している。
特徴
動作
MS-DOSの場合、シングルタスクOSであるため、一旦テンポラリファイルに出力され、次のタスクの入力時に読み込ませている。
UNIXは基本的にはマルチタスクOSなので、MS-DOSとは違い入力と出力が並行して行なわれる。バッファリングの分だけ遅延があるが、結果が即時に処理される。これは、単機能のモジュール化というUNIXの考え方に適った設計といえる。
機構
UNIXにおいて、具体的にパイプがどのように実現されているかというと、その正体はプロセス間通信である。
そもそも、パイプも入出力に関連する機能ではあるが、異なるプロセスで同じ入出力を共有するようなことは出来ない。従って、オペレーティングシステムが仲介し、双方をプロセス間通信で接続しているのである。
UNIXでは、ステムコールpipe()でこれをおこなう。pipe()を呼び出すと、メモリー上にバッファー領域が作られ、この領域を介して二つのプロセスが通信する。この領域はオペレーティングシステムによってファイルとして扱われるため、あたかも通常のファイルを読み書きするかのようにアクセスすることができる。
標準入出力
シェルがパイプ機能を実現するためには、標準入出力の切り替えをする。これによってアプリケーションは、パイプかどうかをあまり意識する必要なく、標準入出力へのアクセスをするだけで、目的が達成される。
しかしこの機能を実現するためには、やや複雑な機構が必要となる。
パイプは、出力先が別のコマンドになる。シェルからは複数のプログラムを実行する必要が生じるが、exec()などのシステムコールではプロセスが実行したコマンドで置き換えられてしまうために、複数のコマンドの入出力を繋げる処理が実現できない。そこでシェルはfork()をして子プロセスとして生成し、ここで出力先のコマンドを実行している。子プロセスには親プロセスのファイルディスクリプターが複写されているため、それを利用できるのである。
こうしてfork()後、出力側は標準出力、入力側は標準入力をそれぞれclose()し、pipe()で得たfdをdup()に与えて標準入出力に切り替えることになる。
再検索