ウィキペディアにおけるパイプについては、「Help:パイプ付きリンク」をご覧ください。
この項目では、プロセス間のパイプ処理について説明しています。並行処理全般については「パイプライン処理」をご覧ください。
ある端末上で3つのパイプで繋いだプログラムを実行する際の入出力の流れ
Unix系オペレーティングシステムのパイプ(pipe)、もしくはパイプライン (pipeline) とは、複数のプログラムの入出力をつなぐための仕組み(プロセス間通信)の一つである。 パイプを使うと、複数のプログラムを組み合わせることができるようになり、多様かつ複雑なデータ処理を効率よく柔軟に実行できる。また、現有のソフトウエア資産の再利用が可能になるため、プログラム生産性の面でも利点もある。 シェルにおける具体的な利用の例は #シェルからの使用を参照。「UNIX哲学」も参照 次にUNIX系OSとpipeとの関係について説明する。 データ処理の一連の過程を一般化すると、入力データ、これを処理するプログラム、出力データの3つの要素で構成される。特に処理が煩雑な場合、プログラムは複雑になり、バグや保守性の悪化を誘発する傾向にある。また特定の複雑な処理のみに特化したプログラムは再利用性も悪く生産性の観点でも劣る。 この問題を解決するために、「1つだけの仕事をうまくやる、道具のようなソフトウェア」(Software Tools)をパイプラインによって組み合わせる、というアイデアがUNIXやUnix系のOSにある。これはまず、ユーザーが複雑なデータ処理を機能毎に小さく分割する事から始まる。次に、この分割された比較的単純な処理を小さくシンプルなソフトウエアで処理させる。ソフトウエアの出力データは、中間結果として、次の小さなソフトウエアの入力データにパスされる(パイプで繋ぐ)。このようにパイプで繋ぐ事を繰り返すことで、複雑な処理を小さくシンプルなソフトウエア群の数珠繋ぎで実現しようとするものである。パイプで連結することを前提とした構成のプログラムをフィルタとも呼ぶ。 直接の親子関係にあるプロセス間で通信をおこなうためfork前にあらかじめ共有しておく「無名パイプ」と、親子関係にないプロセス間で一時ファイルにディレクトリエントリする(接続自体はファイルを経由するわけではない)「名前付きパイプ」がある。ダグラス・マキルロイがUnixシェル向けに考案したことから始まり、パイプライン輸送からの連想で名付けられた[1]。 特に、シェルなどでは縦棒( 。 )の記号を使って無名パイプを簡単に利用でき、それを指して「パイプ」と言うことも多い。プロセス群の標準ストリームを連鎖的に相互接続するもので、あるプロセスの標準出力 (stdout) を直接別のプロセスの標準入力 (stdin) に接続する。 前述のシェルのコマンドラインにおけるパイプは、中置記法で結合法則を満たす演算子と見ることができる(その時、演算子(オペレータ)のオペランドにあたるのは、各プログラムである)。これを一種の「合成」と見ることもできる。一般に数学で、f, g, h という関数があるとして h(g(f(x))) というような計算をすることを考える時、関数を関数合成の演算子 ? で合成した (h?g?f)(x) というものを考えることがあるが、パイプの演算子 。 はこれに似ており ( progF < x ) 。progG 。progH あるいは ( progF 。progG 。progH ) < x となる[2]。 パイプに関連したシグナルとして SIGPIPE がある。パイプの読み出し側が閉じられた後にパイプへの書き込みが行われると、パイプへ書き込もうとしたプロセスへ SIGPIPE を配送する。デフォルト動作では、SIGPIPE を受信したプロセスは異常終了する。パイプから読み出すプロセスがパイプを閉じ、かつパイプへ書き込むプロセスが書き込みを続けるとパイプのバッファは枯渇してしまい、後者のプロセスがブロックしてしまうため、SIGPIPE によりこれを防止している。なお、類似の機能を持つソケットにて同じ状況が発生した場合、書き込み側ではパイプと異なり、実際に書き込んだサイズをゼロとすることにより同様の状況をプロセスに伝える。また、パイプの書き込み側が先に閉じられた場合、読み出し側では End Of File に到達したのと同じ扱いとなり、パイプ独自の処理は行わない。 以下が典型的なパイプの利用例である。|(バーティカルバー) はシェルにパイプを指示する記号である。grep 札幌市 Address.txt 。a2ps 。lpr これは といった処理を指示している。 パイプを使用する方法に対して、中間ファイルを利用する方法grep 札幌市 Address.txt > sapporo.txta2ps < sapporo.txt > print.pslpr < print.ps もあるが、パイプを利用する方法に比べ記述が冗長になるだけでなく、一般に処理が遅くなる。 なぜならば、このように中間ファイルをつくる場合1つ目のプログラムがすべてのデータを処理し終えるのを待って、2つ目のプログラムが動き、さらに2つ目のプログラムが終了して初めて、3つめのプログラムを動かす必要があるためである。しかしパイプを使えば、3つのプログラムをマルチタスクにより同時に動かし、I/Oなど時間がかかる処理の待ち時間を有効に使うことができる。 さらに、逐次処理を行うため、データのサイズが大きい場合でも記憶領域を消費しない利点もある。また、データの受け渡しがメモリ上で行われるため、その点でも高速な処理が期待できる。 また、上記例はパイプや中間ファイルを利用する方法以外にも、プログラミング言語を利用して専用のソフトウエアを作成し処理する方法もある。しかしながら、パイプを利用すれば既存のUNIXコマンドのみで素早く実現したい処理を実現できる。特に一度しか実行しないような処理に対して専用のソフトウエアを作成するのは過剰であり、生産性の面でもパイプは優れている。 UNIXの設計思想である、それぞれの役割に特化したプログラムを組み合わせ、複雑な機能を実現する(ツールキットアプローチ デフォルトでは、パイプ内のプロセスの標準エラーストリーム (stderr) はパイプを通して渡されず、もとのパイプを起動したコンソール(または端末)に出力される。ただし多くのシェルはこの動作を変更する追加構文を用意している。
概要
シェルからの使用
ファイル Address.txt から "札幌市" が含まれる行を出力し
その出力を入力として受け取って a2ps コマンドを用いて整形し
その出力を印刷する
エラーストリーム