1

假设我有一个目录列表,每个目录可能包含也可能不包含我也想考虑的子目录。

假设我有一个时间戳列表,列表中的每个目录都有一个时间戳(但不是子目录)。这些被称为具有隐式时区的日期和时间,因此可以很容易地转换为 Unix 时间戳,如果这样更容易比较的话。

对于列出的每个目录,我如何找出目录中是否存在比我为相关目录拥有的时间戳更新的文件(就 mtime 或 ctime,但不是 atime)?

我对哪个特定文件比时间戳更新并不真正感兴趣,只关心是否存在任何此类文件。

基本上,我想编写一个脚本,如果一组目录中的任何一个目录中的任何文件在给定时间点后发生更改,则在运行时执行特定操作,并且需要想出一种方法来检测是否有任何东西改变了。

4

1 回答 1

7

您的问题可以转化为多个简单的子问题

  1. 问:如何递归查看目录中的每个文件?

    答:use File::Find。这看起来有点像

    use File::Find;
    
    find sub {
      return unless -f;
      if (file_is_newer_than($timestamp)) {
        do something;
      },
    }, $top_dir;
    
  2. 问:如何为多个目录执行此操作?

    A:将其包装在 foreach 循环中,例如

    for my $dir_time (["./foo", 1234567890], ["./bar", 1230987654]) {
      my ($top_dir, $timestamp) = @$dir_time;
      # above code
    }
    
  3. 问:如何确定文件是否较新?

    A:stat它为mtimeor ctime,然后将结果与您的时间戳进行比较。例如

    use File::stat;
    
    say "$_ is new!" if stat($_)->mtime > $timestamp;
    
  4. 问:我只关心是否存在任何此类文件。我怎样才能缩短电路find

    - 答:棘手的一个。我们不能只returnfind, 因为那只会从我们传递给它的 coderef 退出。相反,我们可以使用 exceptions-for-control-flow 反模式:

    eval {
      find {
        wanted => sub {
          return unless -f;
          die "New file found\n" if stat($_)->mtime > $timestamp;
        },
        no_chdir => 1,
      } $top_dir;
    };
    if ($@) {
      # I should really use exception objects here…
      if ($@ eq "New file found\n") {
        say "New file in $top_dir found";
      } else {
        die $@;  # rethrow error
      }
    }
    

    我设置了该no_chdir选项,这样我就不必在异常处理程序中恢复正确的工作目录。

    或者我们可以对标记的块使用循环控制:

    DIR: for my $dir_time (...) {
      my ($top_dir, $timestamp) = @$dir_time;
      RECURSION: {   
        find {
          wanted => sub {
            return unless -f;
            last RECURSION if stat($_)->mtime > $timestamp; # exit the RECURSION block
          },
          no_chdir => 1,
        } $top_dir;
        # if we are here, no newer file was found.
        next DIR; # make sure to skip over below code; go to next iteration
      }
      # this code only reached when a newer file was found
      say "New file found";
    }
    

    虽然这不会滥用控制流的异常,但这会触发警告:

    Exiting subroutine via last
    

    我们可以用no warnings 'exiting'.

注意:这里的所有代码都未经测试。

于 2013-07-28T19:09:52.333 回答