我如何以递归方式读出Perl中的目录?

时间:2010-03-19 09:01:00

标签: perl recursion treeview directory

我想以递归方式读出一个目录,以便在带有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;
}

我怎么能解决这个问题?

6 个答案:

答案 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);

另见:

这是重写您的递归解决方案。注意事项: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;
}