Perl File::Find::Rule
Perl File::Find::Rule
我正在尝试使用 File::Find::Rule
仅将子文件夹的名称(非递归地)复制到一个数组中。我还想排除数组 @exclude_dirs
中提到的目录名称
#!/usr/bin/perl
use strict;
use warnings;
use File::Find::Rule;
use Data::Dumper;
my $basedir = "C:\/Test";
my @exclude_dirs = qw( dir1_excl dir2_excl );
my @subdirs = File::Find::Rule
->directory()
# ->name(@exclude_dirs)->prune->discard, File::Find::Rule->new
->maxdepth(1)
->in( $basedir );
print Dumper(\@subdirs);
期望的输出
$VAR1 = [
'dir1',
'dir2',
'dir3'
]
当前输出
$VAR1 = [
'C:/Test',
'C:/Test/dir1',
'C:/Test/dir1_excl',
'C:/Test/dir2',
'C:/Test/dir2_excl',
'C:/Test/dir3'
]
您尝试的目的:
my @subdirs =
File::Find::Rule
->mindepth(1)
->maxdepth(1)
->directory
->or(
File::Find::Rule
->name(@exclude_dirs)
->discard
->prune,
File::Find::Rule
->new
)
->in($basedir);
可能的优化:
my @subdirs =
File::Find::Rule
->mindepth(1)
->maxdepth(1)
->or(
File::Find::Rule
->name(@exclude_dirs)
->discard
->prune,
File::Find::Rule
->directory
)
->in($basedir);
也就是说,您只需要以下内容:
my @subdirs =
File::Find::Rule
->mindepth(1)
->maxdepth(1)
->not_name(@exclude_dirs)
->directory
->in($basedir);
所有这些 return 完整路径,因此您需要跟进
s{^\Q$basedir\E/}{} for @subdirs;
通常,我会使用 FFR 而不是 readdir
,因为使用 readdir
的时间更长、更复杂且更容易出错。但在这种情况下,它是临界点。
my @subdirs;
{
my %exclude_dirs = map { $_ => 1 } '.', '..', @exclude_dirs;
opendir(my $dh, $basedir)
or die("Can't read dir \"$basedir\": $!\n");
while (my $fn = readdir($dh)) {
next if $exclude_dirs{$fn};
my $qfn = "$basedir/$fn";
if (!stat($qfn)) {
warn("Skipping $qfn\": Can't stat: $!\n");
next;
}
push @subdirs, $fn if -d _;
}
}
use strict;
use warnings;
use Data::Dumper;
my $basedir = "C:/Test";
my @exclude_dirs = qw(. .. dir1_excl dir2_excl);
my $exclude_pat = join('|', map { quotemeta } @exclude_dirs);
opendir(my $dh, $basedir) or die $!;
my @subdirs = grep { -d "$basedir/$_" && !/^(?:$exclude_pat)\z/i } readdir($dh);
closedir($dh);
print Dumper(\@subdirs);
如果要排除的目录不像您的问题中那样动态,则无需在运行时构建正则表达式:
my @subdirs = grep { -d "$basedir/$_" && !/^(?:\.|\.\.|dir1_excl|dir2_excl)\z/i } readdir($dh);
我正在尝试使用 File::Find::Rule
仅将子文件夹的名称(非递归地)复制到一个数组中。我还想排除数组 @exclude_dirs
#!/usr/bin/perl
use strict;
use warnings;
use File::Find::Rule;
use Data::Dumper;
my $basedir = "C:\/Test";
my @exclude_dirs = qw( dir1_excl dir2_excl );
my @subdirs = File::Find::Rule
->directory()
# ->name(@exclude_dirs)->prune->discard, File::Find::Rule->new
->maxdepth(1)
->in( $basedir );
print Dumper(\@subdirs);
期望的输出
$VAR1 = [
'dir1',
'dir2',
'dir3'
]
当前输出
$VAR1 = [
'C:/Test',
'C:/Test/dir1',
'C:/Test/dir1_excl',
'C:/Test/dir2',
'C:/Test/dir2_excl',
'C:/Test/dir3'
]
您尝试的目的:
my @subdirs =
File::Find::Rule
->mindepth(1)
->maxdepth(1)
->directory
->or(
File::Find::Rule
->name(@exclude_dirs)
->discard
->prune,
File::Find::Rule
->new
)
->in($basedir);
可能的优化:
my @subdirs =
File::Find::Rule
->mindepth(1)
->maxdepth(1)
->or(
File::Find::Rule
->name(@exclude_dirs)
->discard
->prune,
File::Find::Rule
->directory
)
->in($basedir);
也就是说,您只需要以下内容:
my @subdirs =
File::Find::Rule
->mindepth(1)
->maxdepth(1)
->not_name(@exclude_dirs)
->directory
->in($basedir);
所有这些 return 完整路径,因此您需要跟进
s{^\Q$basedir\E/}{} for @subdirs;
通常,我会使用 FFR 而不是 readdir
,因为使用 readdir
的时间更长、更复杂且更容易出错。但在这种情况下,它是临界点。
my @subdirs;
{
my %exclude_dirs = map { $_ => 1 } '.', '..', @exclude_dirs;
opendir(my $dh, $basedir)
or die("Can't read dir \"$basedir\": $!\n");
while (my $fn = readdir($dh)) {
next if $exclude_dirs{$fn};
my $qfn = "$basedir/$fn";
if (!stat($qfn)) {
warn("Skipping $qfn\": Can't stat: $!\n");
next;
}
push @subdirs, $fn if -d _;
}
}
use strict;
use warnings;
use Data::Dumper;
my $basedir = "C:/Test";
my @exclude_dirs = qw(. .. dir1_excl dir2_excl);
my $exclude_pat = join('|', map { quotemeta } @exclude_dirs);
opendir(my $dh, $basedir) or die $!;
my @subdirs = grep { -d "$basedir/$_" && !/^(?:$exclude_pat)\z/i } readdir($dh);
closedir($dh);
print Dumper(\@subdirs);
如果要排除的目录不像您的问题中那样动态,则无需在运行时构建正则表达式:
my @subdirs = grep { -d "$basedir/$_" && !/^(?:\.|\.\.|dir1_excl|dir2_excl)\z/i } readdir($dh);