Perlで既存のファイルを書き換える時のBest Practicesは?

何か今日sed -iのようなことをしたくなったのですが、読み書き両用モード(+<)でopenしてseekしてtruncateして云々というのが面倒だったのでテンポラリファイル使ってごにょごにょしてしまいました。
すんなりできる方法を助言を頂きたく。。。

条件

  • ファイル一覧は、抽出条件が複雑なためスクリプト内で生成されます(コマンドラインから与えられません)。
  • できればコアモジュールだけで・・・

※1番目の条件は、ファイル一覧抽出後にそれらを引数にしてexecするという手もありますね。と書いてみたものの、引数が多くなるとダメになってしまうので、この案は却下。

use File::Temp;
use File::Copy;

foreach my $file (qw(foo.txt)) {
    # open temporary file
    my $out = File::Temp->new;

    open my $in, q{<}, $file or die $!;
    while (<$in>) {
        s/foo/bar/;
        print $out $_;
    }
    close $in;
    close $out;

    # rename
    move($out->filename, $file);
}


追記1
id:odzさんにスクリプト内でinplace-editするという方法を教えていただきました!感謝感謝。取り急ぎ報告をば。

my $filelist = ['foo.txt'];
sub main {
    local $^I = "";
    local @ARGV = @$filelist;
    while (<>) {
        s/foo/bar/;
        print;
    }
}

main;

としてみたところ、


Can't do inplace edit on foo.txt: Permission denied at test.pl line 5.
などと言われてfoo.txtが空っぽになって無くなってしまいました・・・(;´Д`)ウウッ…こういう挙動はWindowsならではという感じがするけど。。。
夜も更けているため丸コピ実行しただけなので、明日ちゃんと調べてみようと思います。

xargsは環境によっては無い場合があるので、ちょっと|ι´Д`|っ < むりぽ


追記2
再びid:odzさんからトラックバックをいただきました。
>こっちでは空っぽというより、ファイルそのものが無くなりましたが。
あ、これは書き間違っていました。こちらでもファイルそのものが無くなりました。

my $filelist = ['foo.txt'];
{
    local $^I   = ".bak";
    local @ARGV = @$filelist;
    while (<>) {
        s/foo/bar/;
        print;
    }
    unlink map { $_ . $^I } @$filelist;
}

open,closeが無い分、すっきりしてますね。
ベンチマークでもINPLACE_EDITの方がかなり速いです。

Benchmark: timing 1000 iterations of File::Temp, INPLACE_EDIT...
INPLACE_EDIT:  5 wallclock secs ( 0.75 usr +  2.49 sys =  3.24 CPU) @ 308.17/s (n=1000)
  File::Temp:  8 wallclock secs ( 2.88 usr +  5.11 sys =  7.99 CPU) @ 125.14/s (n=1000)

ということで、
@ARGVを局所化してINPLACE_EDITする(ただし可搬性を高めるためにバックアップファイルを作る)
ってのがBest Practiceっぽいですね。


id:odzさん、どうもありがとうございました。
そして、完全に他人のふんどしで相撲とったことに反省orz...