假设我有一个目录列表,每个目录可能包含也可能不包含我想要考虑的子目录.
我们还说我有一个时间戳列表,一个列表中的每个目录(但不是子目录).这些被称为具有隐式时区的日期和时间,因此可以相当容易地转换为Unix时间戳,如果这样可以更容易比较.
对于列出的每个目录,我如何确定目录中是否存在比我对相关目录的时间戳更新(mtime或ctime,但不是atime)更新的文件?
我真的不知道哪个特定文件比时间戳更新,只是根本不存在任何这样的文件.
基本上,我想编写一个脚本,当运行时执行特定操作,如果在给定时间点之后任何一个目录中的任何一个文件已被更改,并且需要提出一种方法来检测是否有任何内容改变.
您的问题可以转换为多个简单的子问题
问:如何递归查看目录中的每个文件?
A : use File::Find. 这看起来有点像
use File::Find;
find sub {
return unless -f;
if (file_is_newer_than($timestamp)) {
do something;
},
}, $top_dir;
Run Code Online (Sandbox Code Playgroud)问:我如何为多个目录执行此操作?
答:将它包裹在foreach循环中,例如
for my $dir_time (["./foo", 1234567890], ["./bar", 1230987654]) {
my ($top_dir, $timestamp) = @$dir_time;
# above code
}
Run Code Online (Sandbox Code Playgroud)问:如何确定文件是否更新?
答:stat它用于mtime或者ctime,然后将结果与您的时间戳进行比较.例如
use File::stat;
say "$_ is new!" if stat($_)->mtime > $timestamp;
Run Code Online (Sandbox Code Playgroud)问:我只对是否存在任何此类文件感兴趣.我该如何缩短电路find?
A:棘手的.我们不能只是return从find,因为那将从我们传递它的coderef退出.相反,我们可以使用exception-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
}
}
Run Code Online (Sandbox Code Playgroud)
我设置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";
}
Run Code Online (Sandbox Code Playgroud)
虽然这不会滥用控制流的异常,但这会触发警告:
Exiting subroutine via last
Run Code Online (Sandbox Code Playgroud)
我们可以用这个来沉默no warnings 'exiting'.
注意:这里的所有代码都是未经测试的.