如何递归地读出 Perl 中的目录?
Posted
技术标签:
【中文标题】如何递归地读出 Perl 中的目录?【英文标题】:How can I recursively read out directories in Perl? 【发布时间】:2011-01-29 09:08:25 【问题描述】:我想用 Template::Toolkit 递归地读出一个目录来打印 html 页面中的数据结构。 但我一直在思考如何以易于阅读的形式保存路径和文件。
我的想法是这样开始的
sub list_dirs
my ($rootPath) = @_;
my (@paths);
$rootPath .= '/' if($rootPath !~ /\/$/);
for my $eachFile (glob($path.'*'))
if(-d $eachFile)
push (@paths, $eachFile);
&list_dirs($eachFile);
else
push (@files, $eachFile);
return @paths;
我该如何解决这个问题?
【问题讨论】:
【参考方案1】:您应该始终使用严格和警告来帮助您调试代码。例如,Perl 会警告您 @files
未声明。但是您的函数的真正问题是,您在每次递归调用 list_dirs
时都声明了一个词法变量 @paths
,并且在递归步骤之后不要将返回值推回。
push @paths, list_dir($eachFile)
如果您不想安装额外的模块,以下解决方案可能会对您有所帮助:
use strict;
use warnings;
use File::Find qw(find);
sub list_dirs
my @dirs = @_;
my @files;
find( wanted => sub push @files, $_ , no_chdir => 1 , @dirs);
return @files;
【讨论】:
用这个例程我只得到一个结果,这是我给例程启动的目录。 你能告诉我你用来检查这个的代码吗?它在这里工作得很好。也许用“使用 Dumper;打印 Dumper list_dirs '/home'”来测试它。 您能否解释一下find
命令中发生了什么?对于 Perl 新手来说,它看起来很神秘。【参考方案2】:
我认为您的代码中的以下行有问题
for my $eachFile (glob($path.'*'))
您将 $path 变量更改为 $rootpath。
它将正确存储路径。
【讨论】:
【参考方案3】:这应该可以解决问题
use strict;
use warnings;
use File::Find qw(finddepth);
my @files;
finddepth(sub
return if($_ eq '.' || $_ eq '..');
push @files, $File::Find::name;
, '/my/dir/to/search');
【讨论】:
所以,glob 实际上不支持文件的递归列表,对吧? 没错,它只会从给定目录中获取文件。【参考方案4】:mdom 的回答解释了您最初的尝试是如何误入歧途的。我还建议您考虑对File::Find
更友好的替代方案。 CPAN 有几个选项。这是一个。
use strict;
use warnings;
use File::Find::Rule;
my @paths = File::Find::Rule->in(@ARGV);
另见此处:
SO answer 提供 CPAN
File::Find
的替代品。
SO question 在目录迭代器上。
这是对递归解决方案的重写。注意事项:use strict
; use warnings
;以及使用范围块为子例程创建静态变量。
use strict;
use warnings;
print $_, "\n" for dir_listing(@ARGV);
my @paths;
sub dir_listing
my ($root) = @_;
$root .= '/' unless $root =~ /\/$/;
for my $f (glob "$root*")
push @paths, $f;
dir_listing($f) if -d $f;
return @paths;
【讨论】:
【参考方案5】:我使用这个脚本从我的 USB Pendrive 中删除隐藏文件(由 Mac OS X 创建),我通常用它来听汽车中的音乐,以及任何以“.mp3”结尾的文件,即使它以“.mp3”开头“._”,将在汽车音响列表中列出。
#!/bin/perl
use strict;
use warnings;
use File::Find qw(find);
sub list_dirs
my @dirs = @_;
my @files;
find( wanted => sub push @files, $_ , no_chdir => 1 , @dirs);
return @files;
if ( ! @ARGV || !$ARGV[0] )
print "** Invalid dir!\n";
exit ;
if ( $ARGV[0] !~ /\/Volumes\/\w/s )
print "** Dir should be at /Volume/... > $ARGV[0]\n";
exit ;
my @paths = list_dirs($ARGV[0]) ;
foreach my $file (@paths)
my ($filename) = ( $file =~ /([^\\\/]+)$/s ) ;
if ($filename =~ /^\._/s )
unlink $file ;
print "rm> $file\n" ;
【讨论】:
【参考方案6】:您可以将此方法用作分隔特定文件类型的递归文件搜索,
my @files;
push @files, list_dir($outputDir);
sub list_dir
my @dirs = @_;
my @files;
find( wanted => sub push @files, glob "\"$_/*.txt\"" , no_chdir => 1 , @dirs);
return @files;
【讨论】:
以上是关于如何递归地读出 Perl 中的目录?的主要内容,如果未能解决你的问题,请参考以下文章