[[FrontPage]]

#contents

* パイプでつなぐ [#g6c751b8]
1968年、UNIXの産みの親であるKen ThompsonとDennis RitchieがAT&Tのベル研究所でMulticsと呼ばれる大型のオペレーティングシステムを開発していた頃、「インタラクティブで便利なコンピュータサービス」が欲しいと言って作ったのがUNIXです。

彼らは、「ベル研の文書処理システムを作る」と言って予算を引き出し、PDP-11(システムメモリ16Kバイト、ユーザメモリ8Kバイト、ハードディスク512Kバイト)という現在のPDA以下のハードウェアを購入し、その上に現在のUNIXシステムのコマンド群とroffと呼ばれる文書処理システムを構築したのでした。

今では、Linuxの普及により誰でもUNIXの環境を持つことができるようになりました。

** UNIXの3大発明 [#i61b3a24]
今回は、「パイプでつなく」をテーマにUNIXの偉大な大発明の中から、

- fork : 子プロセスの生成
- pipe : パイプ
- リダイレクト

について例題を交えながら説明していきます。

*** パイプを使った処理の例 [#a948992b]
- 単語処理の例

パイプを使った処理の例として、「tr」コマンドのmanページの単語の種類をカウントします。

#pre{{
$ man tr | tr -cs 'A-Za-z' '\n' | sort -u | wc -l
     492

}}

このようにUNIXのコマンドをパイプでつなくことによって簡単に必要な処理をこなすことができます。

- リアルタイムの例

「単語処理の例」は、別にパイプを使わなくてもファイルを使って逐次的に処理できます。
パイプがファイルと決定的に異なる点は、リアルタイムの処理です。

図は、マウスイベントを別Windowにプロットする例です。
&ref(demo_pipeline.jpg);

このデモでは、xevコマンドとEvent2Plot, Graphのシェルスクリプトをパイプでつないで、xplotの画面にイベントをリアルタイムでプロットします。

#pre{{
$ xev | Event2Plot | Graph
}}


** パイプのつなぎ方 [#pfaae892]
pipeシステムコールは、本当に不思議な関数です。自分が出力したものを自分へ送るストリームの輪(パイプ)がpipeシステムによって生成されます。
マニュアルでこのような説明を読んだだけでpipeシステムコールの使い方を理解できる人は少ないでしょう。
マニュアルの説明を読んだだけでpipeシステムコールの使い方を理解できる人は少ないでしょう。

- 最初にパイプを生成します。

&ref(pipe.jpg);

- 次にforkシステムコールを使って、子プロセスを生成します

&ref(fork.jpg);

- 親のin、子のoutをクローズします

&ref(close.jpg);

- 親のstdoutをクローズし、dupします、子のstdinをクローズしてdupします

&ref(dup.jpg);

** パイプを実現する3つのシステムコール [#wece4043]
パイプでつなぐときに必要なシステムコール
- fork
- pipe
- dup

について、おさらいも含めて説明します。

*** fork システムコールのおさらい [#mcf73ea6]
- 親子プロセスがファイルを共有することを確認
- shでstdout,stderrを別ファイルに保存する例
forkシステムコールの仕様は、

#pre{{
呼び出し形式
     #include <unistd.h>

     pid_t
     fork(void);
機能
 呼び出し元のプロセスをコピーして、新しいプロセスを生成する。
戻り値
 成功すると、子プロセスには0が返され、
親プロセスには、子プロセスのプロセスIDが返されます。forkに失敗したら、-1を返します。
}}
です。

forkでは、
- 子プロセスは、変数、ファイルなどのリソースを親システムと共有
- 親と子プロセスは、forkのリターン値で別の処理に切り分けられる

ます。

簡単なプログラムで、上記の仕様を確認してみましょう。
#pre{{
#include <stdio.h>
#include <unistd.h>

main()
{
	int	pid;

	if ((pid = fork()) == 0) {
		// child
		fprintf(stdout, "this is a child process\n");
		fprintf(stderr, "pid(child)=%d\n", pid);
	}
	else {
		// parent
		fprintf(stdout, "this is a parent process\n");
		fprintf(stderr, "pid(parent)=%d\n", pid);
	}
}
}}

以下のようにコンパイルして、実行すると
#pre{{
$ cc -o ex1 ex1.c
$ ex1
this is a parent process
pid(parent)=6556
this is a child process
pid(child)=0
}}
と出力され、分岐とpidの値が正しくセットされていることが分かります。

次に、標準出力(1)とエラー出力(2)をリダイレクトでファイルに保存します。
#pre{{
$ ex1 1>1.out 2>2.out
$ more *.out
<< 1.outの内容 >>
this is a parent process
this is a child process
<< 2.outの内容 >>
pid(parent)=6570
pid(child)=0
}}
と、ファイルが共有されていることが確認できます。

*** pipe システムコールの使い方 [#ka7a7042]
- pipeシステムコールのmanと親子で通信デモ

*** dup システムコールの使い方 [#ic4ba39d]
- dupシステムコールのmanと使い方

** パイプをつなぐCサンプル [#hbf674b0]

** sh でのパイプの使われ方 [#j46d5541]
*** パイプ(|) [#r0f82b15]

*** バックアクセント(`) [#p3d27cbb]

*** ヒアドキュメント(<<EOF) [#u89a4f77]

** 簡単シェルスクリプト [#vf5f7efd]
*** おさらい [#b051ca79]
- リダイレクト
- ファイル展開
- シェル変数と環境変数
- 特殊変数
- クォーティング

*** おきまりのパターン [#a20dec8e]
- 引数チェック
- 各ファイルに対する繰り返し
- 制御コマンド
-- if文
-- while文
-- testコマンド

** シェルスクリプトTIP集 [#x2bd3c3c]
- パイプをまとめる括弧
- バックグラウンド処理
- 縦をよこにする
- 一意なファイル名の生成
- 出力の結合
- 特殊ファイル


 皆様のご意見、ご希望をお待ちしております。 

#comment


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
SmartDoc