「続・初めての Perl」勉強3日目

結構間が空いてしまったが、Perl の勉強再開です><
相変わらずよく分からない。。。

第6章 複雑なデータ構造の操作

練習問題1

5章の練習問題2のプログラムは、実行するたびにデータファイル全体を読み出さなければなりませんでした。しかし、ルータのログは毎日新しく作られていきますので、Professor はログファイルを1つの巨大なファイルにまとめてどんどん処理時間を長くしていくようなことは避けたいと思っています。
データファイルに現状の合計を残し、毎日のログファイルとデータファイルから新しい合計が得られるようにプログラムを書き直してください。

ファイルを生成してうんぬんとかやるのかな?
1日単位でファイルを作っていく方法が分からん。日付を取得するのだろうか。

#!/usr/local/bin/perl -w

use Storable;

my $all ="**all machines**";
my $data_file = "total_bytes.data";

my %total_bytes;
if (-e $data_file) {
    my $data = retrive $data_file;
    %total_bytes = %$data;
}

while (<>) {
    next if /^#/;
    my ($source, $destination, $bytes) = split;
    $total_bytes{$source}{$destination} += $bytes;
    $total_bytes{$source}{$all} += $bytes;
}

store \%total_bytes, $data_file;

my @sources = sort { $total_bytes{$b}{$all} <=> $total_bytes{$a}{$all} } keys %total_bytes;

for my $source (@sources) {
    print "$source: $total_bytes{$source}{$all} total bytes sent\n";
    my @destinations =
        sort { $total_bytes{$source}{$b} <=> $total_bytes{$source}{$a} } keys %{ $total_bytes{$source} };
    for my $destination (@destinations) {
        next if $destination eq $all;
        print "  $source => $destination:",
            " $total_byets{$source}{$destination} bytes\n";
    }
    print "\n";
}

Strable モジュール使うって言っても、本で解説してるのだけじゃここまで書けないと思う。

練習問題2

本当に役立つものにするためには、このプログラムに後どのような機能を追加すべきでしょうか。その機能を実装する必要はありません。

マシン別にログを残すとか?

第7章 サブルーチンへのリファレンス

練習問題1

問題文が長すぎるので省略


gather_mtime_between と言うサブルーチンを作ります。このサブルーチンは、開始と終了の2つのサブルーチンを引数として、2個のコードフレを返します。1つ目のコードレフは File::Find のコールバックとして使われるもので、2つの時間の間に変更されたアイテムの名前だけを集めます。2つ目は、見つかったアイテムのリストを返します。

use File::Find;
use Time::Local;

my $target_dow = 1;  # 日曜が0, 月曜が1 ...
my @starting_directories = (".");

my $seconds_per_day = 24 * 60 * 60;
my ($sec, $min, $hour, $day, $mon, $yr, $dow) = localtime;
my $start = timelocal(0, 0, 0, $day, $mon, $yr);
while ($dow != $target_dow) {
    $start -= $seconds_per_day;  # サマータイムとの切り替えがなければ良いが
    if (--$dow < 0) {
        $dow += 7;
    }
}

my $stop = $start + $seconds_per_day;

my ($gather, $yield) = gether_mtime_between($start, $stop);
find($gather, @starting_directories);
my @files = $yield->();

for my $file (@files) {
    my $mtime = (stat $file)[9];
    my $when = localtime $mtime;
    print "$when: $file\n";
}

サマータイムについてのコメントに注意してください。世界の多くの地域ではサマータイムを実施しており、その開始日と終了日の1日は86,400秒にはなりません。

難しすぎ。そもそもサンプルプログラムがどう動いてるのか理解できないんですが。

sub gather_mtime_between {
    my ($begin, $end) = @_;
    my @files;
    my $gatherer = sub {
        my $timestamp = (stat $_)[9];
        unless (defined $timestamp) {
            warn "Can not stat $File::Find::name: $!, skipping\n";
            return;
        }
        push @files, $File::Find::name if
            $timestamp >= $begin and $timestamp < $end;
    };
    my $fetcher = sub { @files };
    ($gatherer, $fetcher);
}