我正在查看Perl的File::Find
模块并按以下方式尝试:
#!/usr/bin/perl
use warnings;
use strict;
use File::Find;
find({wanted => \&listfiles,
no_chdir => 1}, ".");
sub listfiles{
print $File::Find::name,"\n";
}
现在,当我运行它时,我得到以下输出:
Noob@Noob:~/tmp$ perl test.pl
.
./test.txt
./test.pl
./test1.txt
./hello
./hello/temp.txt
现在,我想通过设置no_chdir=>1
我会让我的代码在没有任何目录的情况下进入任何目录。但输出清楚地表明我的代码正在进入hello
目录并列出其文件。
那么,如何将我的代码更改为ls
,而不是输入任何目录。另外,我在我的文件/目录名前面得到./
可以删除吗?
我使用的是Perl 5.14。
答案 0 :(得分:15)
$File::Find::prune
可用于避免重复进入目录。
use File::Find qw( find );
my $root = '.';
find({
wanted => sub { listfiles($root); },
no_chdir => 1,
}, $root);
sub listfiles {
my ($root) = @_;
print "$File::Find::name\n";
$File::Find::prune = 1 # Don't recurse.
if $File::Find::name ne $root;
}
如果您愿意,可以有条件地设置prune
。
use File::Basename qw( basename );
use File::Find qw( find );
my %skip = map { $_ => 1 } qw( .git .svn ... );
find({
wanted => \&listfiles,
no_chdir => 1,
}, '.');
sub listfiles {
if ($skip{basename($File::Find::name)}) {
$File::Find::prune = 1;
return;
}
print "$File::Find::name\n";
}
no_chdir
没有必要 - 它与你要做的事情无关 - 但我喜欢它的作用(阻止改变cwd),所以我把它留在了。
答案 1 :(得分:12)
虽然我认为TLP建议使用glob
或opendir
最适合您的情况,但另一种选择是使用File::Find::Rule - Find::File的界面--with maxdepth(1)
停止目录递归:
use Modern::Perl;
use File::Find::Rule;
my $directory = '.';
my @files = File::Find::Rule->maxdepth( 1 )
->file
->name( '*.txt' )
->in( $directory );
say for @files;
在这种情况下,只有*.txt
个文件名会传递给@files
。
示例输出:
A.txt
B.txt
columns.txt
data.txt
答案 2 :(得分:4)
最简单的方法是使用preprocess
参数从正在处理的每个目录中删除所有目录。这意味着它永远不会下降到指定要搜索的目录
传递给preprocess
子例程的参数列表是当前目录中的节点 - readdir
的输出。返回的值是相同的列表,但根据您希望如何处理它们进行排序和筛选。此代码只删除所有目录
删除初始./
的最佳方法是使用File::Spec
中的rel2abs
。请注意,启用no_chdir
会破坏代码,因为默认情况下rel2abs
将当前工作目录作为基本目录。使用no_chdir
意味着显式传递基本目录参数
use strict;
use warnings;
use File::Find 'find';
use File::Spec;
find({ wanted => \&listfiles, preprocess => \&nodirs }, '.');
sub nodirs {
grep ! -d, @_;
}
sub listfiles {
my $filename = File::Spec->abs2rel($File::Find::name);
print $filename, "\n";
}
答案 3 :(得分:0)
使用预处理和“想要的”
use File::Find qw( find );
my @f;
find(
{
wanted => sub {},
preprocess => sub {
push(@f, grep !/^\.?\./,@_); # @_ is equivalent to readdir(DIR)
# '.' and '..' come for free
# find uses what you return here for processing.
# since nothing (an empty list) is returned, it has nothing to recurse on
}
},
@dirs);
如果你想要完整的路径,那么像这样映射grep
push(@f, map { Spec->catfile($File::Find::dir,$_); } grep !/^\.?\./,@_);
或者,只是
push(@f, map { $File::Find::dir . '/' . $_); } grep !/^\.?\./,@_);
对于后者,您可能会在Windows上获得\和/的混合,具体取决于您如何指定@dirs的元素