2008年05月26日 02:30 [Edit]

perl - tac を一行で

camel

それってone-linerで。

[を] さくらのレンタルサーバに tac コマンドを入れる
UNIX 系のコマンドで、tac というのがすごく便利なのです。 これはファイルを先頭から表示する cat というコマンドの逆で、 ファイルを行単位でひっくり返して末尾から表示してくれるのです。

% perl -e 'print reverse <>'

ただし、このやり方は一端メモリーに全ファイルを読み込むので非効率といえば非効率。以下のようにすればもう少し効率的になりますか。

#!/usr/local/bin/perl
use strict;
use warnings;

@ARGV or die "$0 [files...]";

for my $filename ( reverse @ARGV ) {
    open my $fh, '<', $filename or die "$filename:$!";
    my @loc;
    push @loc, tell($fh) while (<$fh>);
    seek $fh, $_, 0 and print scalar <$fh> for ( reverse @loc );
    close $fh;
}
% perl tac.pl tac.pl
}
    close $fh;
    seek $fh, $_, 0 and print scalar <$fh> for (reverse @loc);
    push @loc, tell($fh) while(<$fh>);
    my @loc;
    open my $fh, '<', $filename or die "$filename:$!";
for my $filename (reverse @ARGV){

@ARGV or die "$0 [files...]";

use warnings;
use strict;

ファイルが100万行とかある場合は、拙作Tie::Array::Packを使って以下のように改造するとメモリーを節約できます。

#!/usr/local/bin/perl
use strict;
use warnings;
use Tie::Array::Pack;

@ARGV or die "$0 [files...]";

for my $filename ( reverse @ARGV ) {
    open my $fh, '<', $filename or die "$filename:$!";
    tie my @loc, 'Tie::Array::Pack' => 'N';
    push @loc, tell($fh) while (<$fh>);
    seek $fh, $_, 0 and print scalar <$fh> for ( reverse @loc );
    close $fh;
}

!yojnE

regnoM lreP eht naD


この記事へのトラックバックURL

この記事へのコメント
my @loc=(0);するか、for (reverse 0, @loc)にしないと先頭の行が出ない気が。
Posted by mad-p at 2008年05月26日 23:43
さくらレンタルサーバーならFreeBSDだろうから tail -r でよくね?
Posted by otsune at 2008年05月26日 20:37