Go to the first, previous, next, last section, table of contents.

ファイルハンドル/ファイル名置換

<> で囲んだファイルハンドルを評価すると、 そのファイルから次の行を読み込む (改行を含むので、EOF までは偽にならない。 このときは値として undefined が返る)。 通常はその値を変数に代入する必要があるが、 一つだけ自動的に代入が行われる状況がある。 <ファイルハンドル> のみが while ループの条件である場合は、 (そしてこの場合にかぎり)値は変数 `$_' に自動的に代入される。 (奇妙に思うかも知れないが、 これをほとんどの perl スクリプトにおいて使うであろう。) とにかく、次の例は全て同等である。

while ($_ = <STDIN>) { print; }
while (<STDIN>) { print; }
for (;<STDIN>;) { print; }
print while $_ = <STDIN>;
print while <STDIN>;

ファイルハンドル STDINSTDOUTSTDERR は 予約されている。(stdinstdoutstderr でも動作するが、 パッケージの中ではグローバルではなくローカルな識別子として解釈されるので、 働かない。)

これら以外のファイルハンドルは open 関数を用いて作成する。 (See section open.)

<ファイルハンドル> を配列を要求するコンテキストで用いると、 全入力行の 1 行がそれぞれ 1 要素となる配列が返る。 この方法を使うと簡単に巨大なデータ空間を作ることができるので、 注意して使った方がいい。

ヌルファイルハンドル <> は特殊で、 sed や awk の動作をエミュレートするのに用いる。 <> には、標準入力か、 またはコマンドラインにリストアップした全ファイルから入力される。 これは次のように動作する。

<> を最初に評価すると、配列 ARGV がチェックされ、 ヌルであれば、$ARGV[0]`-' にセットされる。 これは、オープンする時に標準入力となる。 次に配列 ARGV がファイル名のリストとして処理される。次のループ

while (<>) {
     ...            # 各行に対するコード
}

は下と同等である。

unshift(@ARGV, '-') if $#ARGV < $[;
while ($ARGV = shift) {
     open(ARGV, $ARGV);
     while (<ARGV>) {
          ...      # 各行に対するコード
     }
}

違いは、前者は後者ほど書くのが面倒でないということだけであり、 前者でも実際に配列 ARGV をシフトし、 現在のファイル名を $ARGV に代入している。 また、ファイルハンドル ARGV を内部で用いている。

1 番目のファイル名を配列の最初に残しておくかぎり、 最初の <> の前で @ARGV に手を加えることができる。 行番号 ($.) は入力が一つの大きなファイルであるのと同じく、 継続して増える。 (ファイル毎に行番号をリセットする方法については eof の例を参照のこと。 See section eof.)

@ARGV にファイルのリストをセットしたい場合は、そうすればよい。 スクリプトにスイッチを渡したい場合は、 最初に次のようなループを入れればよい。

while ($_ = $ARGV[0], /^-/) {
     shift;
    last if /^--$/;
     /^-D(.*)/ && ($debug = $1);
     /^-v/ && $verbose++;
     ...       # ほかのスイッチ
}
while (<>) {
     ...       # 各行に対するコード
}

<> は一度だけ偽を返す。この後もう一度呼ぶと、 新たな @ARGV リストの処理を行っているものと見なす。 そしてこの時 @ARGV を セットしていない場合は STDIN から入力される。

<> の中の文字列がスカラー変数を参照している場合 (例えば <$foo>)、その変数は 入力が行われるべきファイルハンドルの名前を値として持つ。

<> の中の文字列がファイルハンドルでない場合は、 置換されるべきファイル名パターンであると解釈され、 コンテキストによりファイル名の配列またはリスト内の次のファイル名が返る。 1 レベルの $ の解釈は最初になされるが、 上で述べたように <$foo> は 間接的にファイルハンドルを指すので使えない。 強制的にファイル名置換と解釈させるためには、 {} を入れればよい: <${foo}>

while (<*.c>) {
     chmod 0644, $_;
}

は次と同等である。

open(foo, "echo *.c | tr -s ' \t\r\f' '\\012\\012\\012\\012'|");
while (<foo>) {
     chop;
     chmod 0644, $_;
}

実は、現在の所、後者の方法でインプリメントしている。 (つまり、マシン上に `/bin/csh' がないかぎり スペースなどを含むファイル名についてはうまく働かない。) もちろん、上の操作を行う最も短い方法は

chmod 0644, <*.c>;

である。


Go to the first, previous, next, last section, table of contents.