我想以递归方式读出一个目录,以便在带有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;
}
我怎么能解决这个问题?
答案 0 :(得分:18)
这应该可以解决问题
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');
答案 1 :(得分:8)
您应始终使用严格和警告来帮助您调试代码。 Perl会警告你,例如@files
未被声明。但是你的函数的真正问题是你在每次递归调用@paths
时都声明了一个词法变量list_dirs
,并且在递归步骤之后不会再返回值。
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;
}
答案 2 :(得分:5)
mdom的回答解释了你最初的尝试是如何误入歧途的。我还建议您考虑File::Find
的更友好的替代方案。 CPAN有几种选择。这是一个。
use strict;
use warnings;
use File::Find::Rule;
my @paths = File::Find::Rule->in(@ARGV);
另见:
SO answer提供CPAN
File::Find
的替代方案。
这是重写您的递归解决方案。注意事项: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;
}
}
答案 3 :(得分:3)
我认为您的代码中的以下行存在问题
for my $eachFile (glob($path.'*'))
您将$ path变量更改为$ rootpath。
它将正确存储路径。
答案 4 :(得分:1)
我使用此脚本从我的USB Pendrive中删除隐藏文件(由Mac OS X创建),我通常用它来收听汽车中的音乐,以及任何以“.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" ;
}
}
答案 5 :(得分:0)
您可以将此方法用作分隔特定文件类型的递归文件搜索
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;
}