続・初めてのPerl 第7章 「サブルーチンへのリファレンス」

練習問題の回答をメモ。今回は、かなりひどいプログラムを書いてしまったけど、自戒の念をこめてそのまま貼っておく。ヒントに書いてあった mtime を活用しないで、自力で mtime 相当のものを求めようとしているのがまずい。

#!/usr/bin/perl -w
use strict;
use warnings;
use File::Find;
use Time::Local;

my $target_dow = 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) = &gather_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";
}

sub gather_mtime_between {
  my ($start, $stop) = @_;
  my @result_files;

  my($sec, $min, $hour, $day, $mon, $yr, $dow) = localtime;
  my $now = timelocal(0, 0, 0, $day, $mon, $yr);
  return(
    sub {
      my $since_last_accessed = (-M $_) * $seconds_per_day;
      my $last_accessed_day_in_seconds = $now - $since_last_accessed;
      if ($last_accessed_day_in_seconds >= $start and $last_accessed_day_in_seconds < $stop) {
        push @result_files, $File::Find::name;
      }
    },
    sub {@result_files;},
);
}

# 以下が解答のコード(p.272)
# sub gather_mtime_between {
#   my ($begin, $end) = @_;
#   my @files;
#   my $gatherer = sub {
#     my $timestamp = (stat $_)[9];
#     unless (defined $timestamp) {
#       warn "Can't stat $File::Find::name: $!, skipping\n";
#       return;
#     }
#     push @files, $File::Find::name if $timestamp >= $begin and $timestamp < $end;
#   };
#   my $fetcher = sub { @files };
#   ($gatherer, $fetcher);
# }

反省点

せっかく mtime のヒントが載っていたのに、その意味をよく理解せずにプログラムを組み始めたのがまずかったね。
ファイルの mtime(タイムスタンプの内の一つ)はそのファイルが最後に更新された時間(last modify time in seconds since the epoch)だよ。
「% perldoc -f stat」で確認しようね。