如何递归地读出 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 strictuse 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 中的目录?的主要内容,如果未能解决你的问题,请参考以下文章

如何递归复制目录并在 Perl 中过滤文件名?

perl 递归的删除目录和目录中的文件

如何[递归地]压缩PHP中的目录? [复制]

使用 Perl 分组:找到更快的递归解决方案

数据库表有3列,Id,Name,ParentId,已从数据库读出数据,如何递归成一棵树?

如何递归地查找具有文本模式的文件,不包括某些目录和文件[重复]