2000 年度「計算機基礎論3B」 リダイレクトとパイプ

「a.out」の代わりに「a.out >> filename」とすると、 filename という名前のファイルの最後に a.out の出力結果を追加する。 ファイルがなければ新規に作られる。 これを利用すると、 長い出力を行なうプログラムの結果をあとからエディタでゆっくり見ることができる。 a.out でなく、ほかのコマンドでも同様。

これは出力リダイレクトの一例である。 このページではリダイレクトとパイプについて解説する。

プログラム rev

以下で rev と呼ばれているコマンドは 次の rev.c をコンパイルして得られる実行ファイルを rev と改名したもの、とします。 もしこの rev.c の中にわからない部分があっても、 このページのほかの部分を理解するには差し支えありません。

== rev.c ======================================================================
#include <stdio.h>
#include <string.h>

char buf[4096+1];

int main() {
    int i;

    while (gets(buf) != NULL) {
        for (i = strlen(buf) - 1; i >= 0; i--) {
            putchar(buf[i]);
        }
        putchar('\n');
    }
    return 0;
}
===============================================================================

標準入力と標準出力、フィルタープログラム

コマンドの中には 「キーボードから受け取ったデータを処理し、結果を画面に書く」 というタイプのものがあります。 例えば unix に標準でついているコマンド sort はキーボードから受け取った行をソートして (i.e. 辞書式順序に並べかえて)画面に書きます。 上の rev はキーボードから受け取った各行の中の文字を逆順にして画面に書きます。 行頭で Ctrl+D を打てば 「これでキーボードからの入力はおしまい」 とみなされ、プロンプトに戻ります。

まずはいろいろ試してこれらに慣れてください。

※ 打ち込んだものに(いわゆる)日本語が含まれると、 sort は日本語コード順に並べるので必ずしも読みの順にはならない。 rev は出力がぐちゃぐちゃになることがある。これは手抜き。

※ MS-DOS 上で試すときは Ctrl+D の代わりに Ctrl+Z で終了する。

キーボード(から打ち込むデータ)を「標準入力(standard input)」、 画面(に書かれる結果)を「標準出力(standard output)」と呼びます。 sort は「標準入力を行単位で辞書式順序に並べかえて標準出力に送るプログラム」、 rev は「標準入力の各行を逆順にして標準出力に送るプログラム」、 ということになります。 これらのプログラムは「フィルター」あるいは 「フィルタープログラム」と呼ばれることもあります。 標準入力を取り込み、フィルターを通して標準出力に送る、 という感じだと思います。

引数なしの cat もこの種のコマンドです。 「標準入力をそのまま標準出力に送る」 のですから、 いわば“自明な”フィルターといえるでしょう。

リダイレクトとパイプ

標準入力や標準出力は、下のようにしてファイルに切り換えることができます。 これを 「リダイレクト(redirect)」とか 「リダイレクション(redirection)」と呼びます。 sort や rev でいろいろ試してみるとよいでしょう。 以下しばらく、「prog」で一般のコマンド名を表わすことにします。 この prog に「コマンド名+引数」を代入しても構いません。 たとえば prog が cat filename でもいいのです。

入力リダイレクト

「prog < ifile」とすると、 単に「prog」として起動した後にファイル ifile の内容をキーボードから打ち込んだかのようにプログラム prog が動きます。 これを「入力リダイレクト」といいます。 前もってエディタを使ってデータを打ち込んでおけるので、 データ量の多いときなどに便利です。

例:「sort < file」は file の行をソートして画面に出力します。 「rev < file」は file の各行を逆順にして画面に出力します。

※ ifile の内容が prog の期待していたものと違うと、 いつまでもコマンドが終了しない場合がある。 例えば「quit」と打てば終わる prog に対して 「quit」という行を含まない ifile を読ませてしまった、など。 その場合は Ctrl+C を押して中止する。 sort や rev ではそのようなことは起こらないはず。 なお、MS-DOS ではこうなった場合リセットするしかなかった。;_;

※ メールのファイルなどをソートしてみるとつながりがとんちんかんで面白かったりする。:-)

出力リダイレクト

「prog > ofile」とすると、 プログラム prog の出力結果がファイル ofile の内容となります。 画面には書かれません。 これを「出力リダイレクト」といいます。 出力結果をあとからエディタに読み込んでゆっくり調べたり、 編集して再利用したりできるので便利です。

※ プログラムの中で何か質問してくるような場合、 そのメッセージまで ofile に行ってしまって画面には何も出力されない場合がある。

※ この「<」や「>」 は不等号ではなく方向を表わす矢印のようなものである。 「A < B」と「B > A」では意味が全く違う。

※ すでに ofile があった場合は上書きされる。 すなわち、もしもこのコマンドの実行前に ofile が存在すれば、 その内容は失われる。

「prog >> ofile」とすると、 プログラム prog の出力結果がファイル ofile の内容の最後に追加されます。 画面には書かれません。 実行前に ofile が存在していなければ新規に作られます。 これも「出力リダイレクト」といいます。

例:「ls -la > file」とすれば ls -la した結果 (ディレクトリの一覧)が file の内容となる。 「ls -la >> file」とすれば file の最後に追加される。

「prog < ifile > ofile」や 「prog < ifile >> ofile」 は入力リダイレクトと出力リダイレクトの組合せです。 入力は ifile, 出力は ofile となります。

例:「sort < file >> file2」とすれば file の行をソートした結果を file2 の最後に追加する。

パイプ

「prog1 | prog2」とすると、 prog1 の出力が prog2 の入力になります。 これを「パイプ(pipe)」といいます。

※ 「|」は「\」キーをシフトしながら打つ(ようにできているキーボードが多い)。 縦棒の真ん中に切れ目がある字体とない字体があるが同じものである。

例:「cat file | sort」は file の行をソートして画面に出力する。

※ オプションなしの「ls」はやや特殊で、 「ls | more」とすると「自分の出力はパイプされているぞ!」 と知っていつもとは違った表示のしかたをする。

パイプとリダイレクトの組み合わせも可能です。 「rev < file1 | sort | rev > file2」など。 しかし、この例は 「cat file1 | rev | sort | rev > file2」 と言いかえられますので、 入力リダイレクトとパイプの組み合わせはあまり使わないようです。

日本語コードの変換プログラム nkf もフィルタープログラムです

くわしくは 「日本語のコードについて」 を見てください。


岩瀬順一