在Perl中如何使用递归来搜索目录和子目录并指定深度?

时间:2014-03-02 14:18:26

标签: perl recursion directory subdirectory depth

所以我知道你可以在子程序中使用opendir打开目录,然后使用readdir来读取当前工作目录中的所有文件,然后将所有文件推送到一个数组中。如果它是一个文件则遍历该数组然后打印该文件或将该文件推送到新数组中,否则如果它是一个目录,则递归地再次调用该子程序。我不明白的是,我在这里指定深度。任何帮助是极大的赞赏。


以下是我在您的帮助下找到的解决方案:

 read_dir('test', 1);

 sub read_dir {
    $dir = shift;
    $level = shift;

    chdir ($dir);
    opendir(DIR, '.') or die "Can't open $dir: $!";
    @filesarray = readdir (DIR) or die;
    closedir(DIR);
    my @files;
    foreach my $file (@filesarray) {
        if (-f $file && $file =~ /\.txt$/i){
              push @files, $file;
            } ## end of if

        elsif (-d $file) {
              next if ($file eq ".");
              next if ($file eq "..");
              $dir = $file;
              read_dir($dir, $level+1); ## QUESTION IS HERE?????
         } ## end of elsif
    } ## end of foreach

    foreach my $file1 (@files) {
         print "$file1\n";
    }
} ## end of sub read_dir

2 个答案:

答案 0 :(得分:0)

您可以将参数传递给名为level的递归函数,并将函数调用为recurse(level+1, subdirectory)

无论如何,最好使用像File::Find这样的专业库来完成这项任务。

答案 1 :(得分:0)

不过,这是一项很好的运动并且可以消除懒惰...

<pre><code>

#!/usr/bin/perl
use DirFind;
my $max = shift(@ARGV);
my $dir = shift(@ARGV);
my $filter = shift(@ARGV);
my %args = (
    maxdepth => $max,
    dirs => $dir,
    filter => $filter
);
# recursive
my $df_r = DirFind->new(%args);
print join("\n", $df_r->reader_r()->result_files()),"\n\n";
exit;

package DirFind;

#
# essentially mimic find
#

#
# we'll be storing things away so we want an object
#
sub new {
    my ($class, @rest) = @_;
    my $self = bless({@rest}, $class);
    # for the sake of all things being equal manufacture the level
    # and translate to listref context so that the new() args can
    # be just the simpler dirs => path
    my $dir = $self->{dirs};
    $self->{dirs}->[0] = join(' ', $dir, 0);
    return $self;
}

#
# with tail recursion we need to store the filter and depth in new()
#
sub reader_r {
    my ($self) = @_;
    my ($d, $lvl) = split(' ', shift(@{$self->{dirs}}));
    # no more directories
    return if (!defined($d) || !defined($lvl));
    return if ($lvl == $self->{maxdepth});
    $lvl++;
    # making the regex a bit more protected
    my $filter = $self->{filter};
    opendir(my $dh, $d);
    my @basefiles = readdir($dh);
    closedir($dh);
    foreach my $f (@basefiles) {
        next if ($f =~ /^\.{1,2}$/);
        my $file = join('/', $d, $f);
        # implicitly skip symlinks
        push(@{$self->{dirs}}, join(' ', $file, $lvl)) if (-d $file);
        if (-f $file) {
        if (defined($filter)) {
            next unless ($file =~ m!$filter!);
            push(@{$self->{files}}, $file);
        }
        }
    }
    if (@{$self->{dirs}}) {
        $self->reader_r();
    }
    # for chaining
    return $self;
}

#
# the recursive form requires the additional call to get the results
# no we chain them
#
sub result_files {
    my ($self) = @_;
    return wantarray? @{$self->{files}}: $self->{files};
}
1;
</code></pre>