使用File :: Find模块时没有输出

时间:2016-04-21 03:13:15

标签: perl closures subroutine

我想计算modify_time介于$atime$btime之间的文件总数。这是我的代码的一部分,但它不会返回任何内容。有什么问题?

sub mtime_between {
    my $mtime=0;
    my $counts=0;
    $mtime = (stat $File::Find::name)[9] if -f $File::Find::name;
    if ($mtime > $atime and $mtime < $btime) {
        return sub { print ++$counts,"$File::Find::name\n"};
    }

当我调用子程序时,我什么都没得到。

find(\&mtime_between,"/usr");

2 个答案:

答案 0 :(得分:4)

你不应该返回一个功能。

检查File::Find documentation

  

find()按照给定的顺序对给定的@directories进行深度优先搜索。对于找到的每个文件或目录,它会调用&wanted子例程。

在想要的功能中,你应该直接做你想做的事情。返回函数引用将不起作用,这就是您遇到问题的原因。

所以你真的想要更像的东西:

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw{say};
use File::Find;
use Data::Dumper;

my ($atime, $btime) = (1461220840, 1561220844);

sub findFilesEditedBetweenTimestamps {
    my ($atime, $btime, $path) = @_;
    my $count = 0;
    my @files = ();

    my $mtime_between = sub {
        my $mtime = 0;
        $mtime = (stat $File::Find::name)[9] if -f $File::Find::name;
        if ($mtime > $atime and $mtime < $btime) {
            push @files, $File::Find::name;
            $count++;
        }
        return;
    };

    find ($mtime_between, $path);

    say "Found a total of $count files";
    say "Files:";
    print Dumper(@files);
}

findFilesEditedBetweenTimestamps($atime, $btime, "./");

我明白了:

Found a total of 2 files
Files:
$VAR1 = './test.txt';
$VAR2 = './test.pl';

答案 1 :(得分:2)

如前所述,wanted子例程返回的值被忽略。从回调中返回回调可能对某些人来说太过分了!

这可能是有意义的。我已经使用File::stat模块来提取修改时间更具可读性Time::Piece,以便$atime$btime可以用可读字符串而不是epoch来表示值

除非您愿意,否则无需为wanted函数编写单独的子例程 - 您可以在find调用中使用匿名子例程。如果节点不是文件,那么从return子例程中简单地wanted是最容易的

#!/usr/bin/env perl

use strict;
use warnings 'all';

use File::Find;
use File::stat;
use Time::Piece;

sub count_files_between_times {

    my ($from, $to, $path) = @_;
    my $count = 0;

    find(sub {
        my $st = stat($_) or die $!;
        return unless -f $st;
        my $mtime = $st->mtime;
        ++$count if $mtime >= $fromand $mtime <= $to;
    }, $path);

    print "Found a total of $count files\n";
}

my ($from, $to) = map {
    Time::Piece->strptime($_, '%Y-%m-%dT%H:%M:%S')->epoch;
} '2016-04-19T00:00:00', '2019-04-22T00:00:00';

count_files_between_times($from, $to, '/usr');


更新

有些人更喜欢File::Find::Rule模块。就个人而言,我非常不喜欢它,看过源代码后我非常警惕它,但它确实使这个过程更加简洁

请注意,File::Find::Rule位于File::Find之上,对此进行了繁重的处理。因此,它本质上是一种编写wanted子程序

的不同方式
use File::Find::Rule ();

sub count_files_between_times {

    my ($from, $to, $path) = @_;

    my @files = File::Find::Rule->file->mtime(">= $from")->mtime("<= $to")->in($path);

    printf "Found a total of %d files\n", scalar @files;
}

或者如果您愿意,可以一次添加一个语句

use File::Find::Rule ();

sub count_files_between_times {

    my ($from, $to, $path) = @_;

    my $rule = File::Find::Rule->new;
    $rule->file;
    $rule->mtime(">= $from");
    $rule->mtime("<= $to");
    my @files = $rule->in($path);

    printf "Found a total of %d files\n", scalar @files;
}

这两个替代子程序产生的结果与上述原始结果相同