特殊変数 $^I の使い方

1つのディレクトリに含まれる大量のファイルに対して、一括で変更を行いたい場合

my $target = "*.dat";

@ARGV = glob $target or die;
$^I = ".bak"; # これがスイッチ

while(<>) {
  s/(^Date:).*/\1 2009-8-10/; # Date ヘッダを 8/10 にして
  s/^Phone: .*\n//;  # 電話番号行を消して。
  print;
}
unlink glob $target or die; # 無事終わったら後始末

ワンライナーだと

% perl -p -i.bak -w -e 's/Kamei/John/g' *.dat

こんなん。

@ARGV を使わないといけないってのが何ともアレな感じではあるが、すげー便利であることは否めない。実際使う場合は @ARGV が変わんないように、ブロックで囲んで

{
  ...
  local @ARGV = glob $target or die;
  ...
}

としといた方がいいだろう。


関数にするんなら、無名関数を引数にとって、

sub replace_all {
  my ($func, $file_glob) = @_;

  local @ARGV = glob "$file_glob" or return 0;
  local $^I = ".bak"; 
  my $cnt = 0;
  while(<>) {
    $cnt += $func->();
    print;  
  }
  unlink glob "$file_glob.bak" or die; 
  return $cnt;
}

ってかんじか。呼び出し元は、以下のような感じで、*.dat のファイルの中に現れる "singer" という文字列を全部 "writer" に置換する感じ。

replace_all(sub{ s/singer/writer/g }, "*.dat");

こういうのシンプルに書けるのが Perl のいいとこだなーと思う。