パイプ (コンピュータ)

Unix系OSにおけるパイプ(pipe)とパイプライン(pipeline)



Unix系オペレーティングシステムにおけるパイプとは、複数のプログラムの入出力を接続するためのプロセス間通信の一種です。パイプを使用することで、複数のプログラムを組み合わせて、多様で複雑なデータ処理を効率的かつ柔軟に実行できます。

パイプの概要



パイプを使用する主な利点は以下の通りです。

複雑な処理の効率化: 複数のプログラムを組み合わせることで、複雑なデータ処理を効率的に実行できます。
既存ソフトウエアの再利用: 既存のソフトウェア資産を再利用することで、プログラムの生産性を向上させます。
処理の分割と組み合わせ: 複雑な処理を小さな機能に分割し、それぞれの機能を担当するプログラムを組み合わせて処理を行います。これにより、プログラム全体の複雑さを軽減し、保守性を向上させます。

UNIX系OSとパイプの関係



データ処理は一般的に、入力データ、処理を行うプログラム、そして出力データの3つの要素で構成されます。特に複雑な処理を行う場合、プログラム自体が複雑になり、バグや保守性の低下を引き起こしやすくなります。また、特定の複雑な処理に特化したプログラムは、再利用性が低く、生産性の観点からも問題があります。

この問題を解決するために、UNIX系OSでは「1つのことをうまくやる、道具のようなソフトウェア」をパイプラインで組み合わせるという考え方が採用されています。具体的には、複雑なデータ処理を機能ごとに小さく分割し、それぞれの機能に対してシンプルなソフトウェアを作成します。そして、各ソフトウェアの出力を次のソフトウェアの入力にパイプで接続することで、複雑な処理を連携して実現します。

パイプで連結されることを前提としたプログラムをフィルタと呼びます。パイプには、直接親子関係にあるプロセス間で通信を行う「無名パイプ」と、親子関係にないプロセス間で一時ファイルを用いて通信を行う「名前付きパイプ」があります。

シェルでのパイプの利用



シェルでは、縦棒(|)の記号を使って無名パイプを簡単に利用できます。この記号は、あるプロセスの標準出力(stdout)を、次のプロセスの標準入力(stdin)に直接接続します。

シェルのコマンドラインにおけるパイプは、中置記法結合法則を満たす演算子とみなすことができます。例えば、関数 f, g, h があるとき、`h(g(f(x)))` という計算を `(h∘g∘f)(x)` と合成関数で表現するのと同様に、`progF < x | progG | progH` は、各プログラムをパイプで繋ぎ合わせることで一連の処理を表現します。

パイプに関連するシグナル



パイプの読み出し側が閉じられた後に、パイプへの書き込みが行われた場合、書き込もうとしたプロセスには `SIGPIPE` シグナルが送られます。このシグナルを受け取ると、プロセスは通常異常終了します。これは、パイプのバッファが枯渇し、書き込み側がブロックされるのを防ぐための仕組みです。

シェルからの使用例



以下は、パイプの典型的な使用例です。

bash
grep 札幌市 Address.txt | a2ps | lpr


この例では、`Address.txt` ファイルから「札幌市」を含む行を `grep` コマンドで抽出し、その結果を `a2ps` コマンドで整形し、最後に `lpr` コマンドで印刷します。

パイプを使用しない場合、中間ファイルを利用する必要があり、記述が冗長になるだけでなく、一般的に処理も遅くなります。パイプを使用することで、複数のプログラムを同時に実行し、I/Oなどの待ち時間を有効に活用できるため、処理を高速化できます。

パイプの利点



処理速度の向上: パイプを使用することで、中間ファイルの書き込みを省略できるため、処理を高速化できます。
メモリ使用量の削減: パイプは逐次処理を行うため、データサイズが大きい場合でもメモリを大量に消費することはありません。
柔軟な組み合わせ: 既存のUNIXコマンドを自由に組み合わせることで、様々な処理を迅速に実現できます。
生産性の向上: 専用のソフトウェアを作成するよりも、パイプを使用する方が効率的で生産性が高い場合があります。

エラーストリーム



デフォルトでは、パイプ内のプロセスの標準エラーストリーム(stderr)はパイプを通して渡されず、起動したコンソールに出力されます。しかし、多くのシェルでは、標準エラーストリームもパイプに渡すための追加構文が用意されています。

Pipemill



シェルをパイプ処理に直接関与させることも可能です。このような技法を「pipemill」と呼びます。

プログラムによるパイプの作成



`pipe()` システムコールを使用すると、プログラム内で新しいパイプ(無名パイプ)を作成できます。`fork()` システムコールと組み合わせて使用することで、親子関係にあるプロセス間で通信を行うことができます。

名前付きパイプ



UNIX'>[POSIX]では、`mkfifo()` または `mknod()` を使用して、ファイルシステムの名前空間に「名前付きパイプ」を作成できます。名前付きパイプを使用することで、親子関係にない任意のプロセス間でパイプ通信を行うことができます。

パイプの実装



通常、OSはパイプのバッファリング機能を提供します。これにより、送信側と受信側の処理速度が異なる場合でも、データの損失を防ぐことができます。

ネットワークパイプ



`netcat` などのツールを使用すると、パイプをTCP/IPソケットに接続することもできます。

パイプの歴史



パイプの概念と縦棒(|)による記法は、初期のUnixシェル開発に関わったダグラス・マキルロイが考案しました。1973年にケン・トンプソンUNIXにパイプを実装し、その後、多くのオペレーティングシステムのコマンドラインシェルに採用されました。

UNIX系以外のOSでのパイプ



MS-DOS: MS-DOSでは、パイプは中間ファイルによってエミュレートされています。
* Windows: Windowsでは、名前付きパイプと匿名パイプが利用可能です。特に、プロセス間通信においては、名前付きパイプが高速に動作します。

まとめ



パイプは、UNIX系OSにおける重要な概念であり、効率的なデータ処理を実現するための強力なツールです。パイプを理解し、適切に活用することで、より柔軟で効率的なシステムを構築できます。

もう一度検索

【記事の利用について】

タイトルと記事文章は、記事のあるページにリンクを張っていただければ、無料で利用できます。
※画像は、利用できませんのでご注意ください。

【リンクついて】

リンクフリーです。