パイプ (コンピュータ)
Unix系オペレーティングシステムにおけるパイプ(pipe)、もしくはパイプライン (pipeline) とは、複数のプログラムの入出力をつなぐための仕組みの一つである。プロセス群の標準ストリームを連鎖的に相互接続するもので、あるプロセスの標準出力 (stdout) を直接別のプロセスの標準入力 (stdin) に接続する。このような接続の実装をテンプレート:仮リンクと呼ぶ。このアイデアはUNIXやUnix系のOS以外にも、MS-DOS をはじめとする様々なOSやアプリケーションに、動作に多少の違いはあるものの受け継がれている。パイプで連結することを前提とした構成のプログラムをフィルタと呼ぶ。
テンプレート:仮リンクがUnixシェル向けに考案したもので、パイプライン輸送からの連想で名付けられた[1]。
UNIXのパイプはテンプレート:仮リンクで中置記法の演算子と見ることができ、そのオペランドはパラメータ付きのプログラムである。プログラム的観点ではパイプ内の全プログラムは同時(並列)に動作すると見なせるが、構文的には左から順に実行されると見ることができる。パイプは一種の写像の合成である。関数型プログラミングで、ある関数の出力を別の関数の引数(入力)として渡すのに似ている。
目次
シェルからの使用
以下が典型的なパイプの利用例である。|(バーティカルバー) はシェルにパイプを指示する記号である。
grep 札幌市 Address.txt | a2ps | lpr
これは
- ファイル Address.txt から "札幌市" が含まれる行を出力し
- その出力を入力として受け取って a2ps コマンドを用いて整形し
- その出力を印刷する
といった処理を指示している。
パイプを使用する方法に対して、中間ファイルを利用する方法
grep 札幌市 Address.txt > sapporo.txt a2ps < sapporo.txt > print.ps lpr < print.ps
もあるが、パイプを利用する方法に比べ記述が冗長になるだけでなく、一般に動作が遅くなる。なぜなら、このように中間ファイルをつくる場合1 つ目のプログラムがすべてのデータを処理し終えるのを待って 2 つ目のプログラムが動かし、さらに2 つ目のプログラムが終了して初めて 3 つめのプログラムが動かす必要がある。しかしパイプを使えば、 3 つのプログラムをマルチタスクにより同時に動かし、I/Oなど時間がかかる処理の待ち時間を有効に使うことができる。さらに、逐次処理を行うために、データのサイズが大きい場合でも記憶領域を消費しない利点もある。また、データの受け渡しがメモリ上で行われるため、その点でも高速な処理が期待できる。
ただし、MS-DOS におけるパイプは、シングルタスク OS という制約のためパイプの動作は中間ファイルによってエミュレートされており、これらの利点はなく単なる略記法となっている。
UNIX の設計思想である、それぞれの役割に特化したプログラムを組み合わせ、複雑な機能を実現する(ツールキットアプローチ、分割統治法)として、パイプはその成功例であり、UNIX を利用する大きな魅力のひとつとなる。
エラーストリーム
デフォールトでは、パイプ内のプロセスの標準エラーストリーム (stderr) はパイプを通して渡されず、元もとのパイプを起動したコンソール(または端末)に出力される。ただし多くのシェルはこの動作を変更する追加構文を用意している。例えば csh の場合、"|
" の代わりに "|&
" を使えば、標準エラーストリームも標準出力と共にパイプでつながれた後続のプロセスに渡される。Bourne Shell では 2>&1
という書き方をし、それだけでは単なるリダイレクトなので、さらにパイプ(バーティカルバー)を記述する。
Pipemill
通常の単純なパイプ使用法では、シェルがパイプを設定して各コマンドを起動すると、後はそれらコマンドが自動的にパイプ処理を行う。従って、パイプ処理中はシェルがそのデータ処理に関与することはない。
しかし、シェルをパイプ処理に直接関与させることもできる。その場合、一般に次のような構文になる。
command | while read var1 var2 ...; do
# $var1, $var2 といった変数を使って行毎に処理
# (なお、この場合の while ループはサブシェルとして実行されるので
# 変数はwhileループが終了した後は使えなくなる)
done
このような技法を "pipemill" とも言う。
プログラムによるパイプの作成
パイプはプログラムの制御の下で作成することもできる。pipe()
システムコールはオペレーティングシステムに新しいテンプレート:仮リンクオブジェクトを生成するように要求する。この結果、2つの新しいファイル記述子が開かれ、プロセスに渡される。つまり、読み取り専用のパイプの口と書き込み専用のパイプの口である。これらパイプの口は、シークができないことを除いて通常の匿名ファイル記述子と同様に扱える。読み取り専用のパイプに対する読み出し命令は、書き込み専用のパイプに対してflushされるまでブロックされる。
デッドロックを避けたり並列処理をしたりするために、1つまたはそれ以上の新しいパイプをもつプロセスは、新しいプロセスを生成するのに、一般的に fork()
を呼び出す。それぞれのプロセスは、データを作り出したり利用したりする前に、使われることのないパイプの口を閉じるだろう。または、最初のプロセスが単純に新しいスレッドを生成し、ただひとつのスレッドがひとつのパイプの口の利用を保証するようにするという方法もある。
書き込み用のパイプと読み出し用のパイプを異なるプロセスが持つことで、ストリームを共有し、協調的な動作を行わせることができる。これはforkした親子関係にあるプロセス間のプロセス間通信で使われる。
名前付きパイプ
テンプレート:Main
またPOSIX(UNIX)では、mkfifo()
または mknod()
を使ってファイルシステムの名前空間に名前付きパイプを作成でき、入力ファイルまたは出力ファイルとしてプログラムから使用できる。それによって複数経路のパイプが作成でき、親子関係にない任意のプロセス間で通信を行うことができる。標準エラーのリダイレクトや tee
と組み合わせればさらに効果的である。
Windowsでは、名前付きパイプを作成するサーバ側は、CreateNamedPipe() で「\\.\pipe\パイプ名」という形式の名前で作成すれば、パイプにつなぐクライアント側からファイルの読み書きと同じ操作で読み書きすることができる。また、Windows における匿名パイプは、ランダムな名前の名前付きパイプとして実装されている。
マシン間の通信にも名前付きパイプを利用することができるが、データを送るたびに、通信確認のためのデータが行き来するので、他のマシンと大量のデータを通信するときは、ソケットの方が高速である。ただし、マシン内のプロセス間通信の場合は、Windowsではカーネル内で動作するので名前付きパイプは高速である。
実装
多くのUnix系システムでは、パイプを構成する全プロセスは入出力が適切に相互接続された状態で同時に起動し、同じマシン上の他のプロセスと同様にスケジューリングされる。このとき重要な観点として、パイプの仕組みであるバッファリングがOS側で提供されている。例えば、あるプロセスが毎秒5000バイトのデータをパイプに送り込み、受け取る側のプロセスが毎秒100バイトしか処理できないとする。それでもデータは失われない。実際にはカーネル内で送信側プログラムの出力がキューに保持され、受信側プログラムがデータ読み取り可能となったとき、カーネルがキューからデータを送り、キュー上で送信済みとなったデータを削除する。キューの容量上限までデータが溜まると、送信側プロセスがブロックされ、受信側が溜まったデータを処理するのを待ち合わせる。Linuxではこのバッファの大きさは65536バイトとなっている。
ネットワークパイプ
netcatなどのツールを使えば、パイプをTCP/IPソケットに接続できる。
歴史
パイプラインの概念とバーティカルバーによる記法は、初期のUnixシェル開発に関わったテンプレート:仮リンクが考案した。彼は、あるプログラムの出力を別のプログラムの入力とするような処理が非常に多いことに気付き、パイプを考案するに至った。そのアイデアを1973年、ケン・トンプソンがUNIXにパイプとして実装した[2]。その後、DOS、OS/2、Microsoft Windows、BeOSといったOSにほぼ同じ記法でパイプが採用されていった。
UNIXのパイプ以前に似たような機構として、1960年代に Ken Lochner がDTSS上で 'communication files' という機構を実装しているが[3]、UNIXのパイプはそれとは独立に開発された[4]。
アップルのAutomatorのアイコンはパイプを持ったロボットだが、これもパイプラインの概念を応用したソフトウェアである[5]。
脚注
関連項目
外部リンク
- History of Unix pipe notation
- Doug McIlroy’s original 1964 memo - パイプの概念を初めて提案した際のメモ
- pipe - SUS man page
- Pipes: A Brief Introduction by The Linux Information Project (LINFO)
- Unix Pipes – powerful and elegant programming paradigm (Softpanorama)
- Ad Hoc Data Analysis From The Unix Command Line at Wikibooks – 単純なフィルタをパイプで組み合わせて複雑なデータ解析を行う方法を解説
- Use And Abuse Of Pipes With Audio Data
- A Q&A about bash pipeline handling – stackoverflow.comsv:Vertikalstreck#Datavetenskap