北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

while

行番号を付けてファイルを表示するスクリプトを書きました。

open(IN, $ARGV[0]) || die;
while(<IN>){
    chomp;
    printf("%04d:%s\n", $., $_);
}
close(IN);

【結果】
$ perl number.pl Test.m
0001:#import <objc/Object.h>
0002:#import <stdio.h>
0003:
0004:@interface Test : Object
0005:{
0006:  int cnt;
0007:}
0008:@end
0009:
0010:@implementation Test
0011: - (void) init{
0012:  self->cnt = 0;
0013:}
 ... 以下省略 ...

ついでにheadの機能をつけてみました。whileの中に行数を絞るロジックを追加しています。

open(IN, $ARGV[0]) || die;
while($. < $ARGV[1] && <IN>){
    chomp;
    printf("%04d:%s\n", $., $_);
}
close(IN);

【結果】
$ perl number.pl Test.m 5 
0001:
0002:
0003:
0004:
0005:

・・・あれ? 行の内容が表示されなくなってしまいました。なんでだろう?


perldocの和訳によると、$_が使われる場合についてこう書かれてます。

【以下の 2つは同値です:】
while (<>) {...} # equivalent only in while!
while (defined($_ = <>)) {...}

Perl が(あなたが使いたくなくても) $_ を仮定する場合がいくつかあります。】
が単独で while テストでテストされた場合の 結果を入れるデフォルトの場所。 while テスト以外ではこれは起こりません。

「単独で」が条件になっています。なので、whileの中に余計な条件文を足すと、このご利益は消えてしまうと言うわけです。

こうしてみると、perlって微妙な挙動が非常に難しいですねえ。