如何使用Perl列出目录中的所有文件?

13

我通常使用类似以下的方法:

my $dir="/path/to/dir";
opendir(DIR, $dir) or die "can't open $dir: $!";
my @files = readdir DIR;
closedir DIR;

有时我使用glob,但无论如何,我总是需要添加一行或两行来过滤掉 . .. ,这非常烦人。您通常如何处理此常见任务?


7
从回复的激增中,可以看出结果完全取决于您想要获得什么。 :) - Ether
可能是重复的问题,参考 *如何在Perl中读取目录内容?*。 - Peter Mortensen
6个回答

14
my @files = grep {!/^\./} readdir DIR;

这也将排除所有的点文件,但这通常是您想要的。


9

我经常使用File::Slurp。它的好处包括:(1)如果目录不存在,它会自动停止运行。(2)默认情况下排除...。它的行为类似于readdir,不返回完整路径。

use File::Slurp qw(read_dir);

my $dir = '/path/to/dir';
my @contents = read_dir($dir);

另一个有用的模块是File::Util,它在读取目录时提供了许多选项。例如:

use File::Util;
my $dir = '/path/to/dir';
my $fu = File::Util->new;
my @contents = $fu->list_dir( $dir, '--with-paths', '--no-fsdots' );

1
这不是OP的要求。他只想过滤掉 ... - CanSpice
很好。我能让它返回完整路径吗?(而不是基本名称) - David B
@David B 你可能也应该考虑使用 File::Util,就像编辑后的答案所示。 - FMc

8

我通常会使用 glob 方法:

for my $file (glob "$dir/*") {
    #do stuff with $file
}

这个方法在目录文件较少的情况下运行良好。但是如果目录中有大量文件,那么你需要回到readdir并使用while循环(将readdir放入列表上下文与glob一样糟糕):

open my $dh, $dir
    or die "could not open $dir: $!";

while (my $file = readdir $dh) {
    next if $file =~ /^[.]/;
    #do stuff with $file
}

通常情况下,如果我需要读取一个目录中的一堆文件,我希望以递归方式读取它们。在这种情况下,我会使用File::Find

use File::Find;

find sub {
    return if /^[.]/;
    #do stuff with $_ or $File::Find::name
}, $dir;

使用 [.] 很奇怪 - 为什么你更喜欢它而不是 \. - C. K. Young
1
@Chris Jester-Young 我只是更喜欢这种方式。它似乎更清晰(参见倾斜牙签综合症)。此外,这是有理的,正则表达式中的转义通常意味着“下一个字符会执行某些特殊操作”(例如\x{2e}),但是\.表示它只是一个句号。由于大多数字符在字符类中没有特殊含义,因此它成为了一个很好的转义机制。 - Chas. Owens

7
如果一些点文件很重要,
my @files = grep !/^\.\.?$/, readdir DIR;

仅会排除...


4
好吧,这可能会排除在Unix中合法的“..\n”。虽然我不希望任何人使用这样的文件名,但有些人会做一些奇怪的事情,以查看是否有人会忽略他们悄悄放入您目录中的文件。您可以使用\z而不是$来解决这个问题 :) - brian d foy

5

当我只想要文件(而不是目录)时,我使用带有-f测试的grep

my @files = grep { -f } readdir $dir;

6
只有当目录句柄为当前目录时,这才有效。 - C. K. Young
1
@Chris:说得好,需要先chdir,或者在grep中使用File::Spec->catfile($dirname, $_)构造绝对路径名。 - Ether

0
感谢Chris和Ether的建议。我使用以下代码将除了目录之外的所有文件列表(从引用非当前目录的目录句柄)读入数组中。当在grep语句中不使用绝对路径时,该数组总是缺少一个文件。
use File::Slurp; 

print "\nWhich folder do you want to replace text? " ;
chomp (my $input = <>);
if ($input eq "") {
print "\nNo folder entered exiting program!!!\n";
exit 0;
} 

opendir(my $dh, $input) or die "\nUnable to access directory $input!!!\n"; 

my @dir = grep { -f "$input\\$_" } readdir $dh;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接