【问题标题】:How can I recursively read out directories in Perl?如何递归地读出 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;
}

我该如何解决这个问题?

【问题讨论】:

    标签: perl recursion treeview directory


    【解决方案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);
      

      另见此处:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-01-29
            • 1970-01-01
            • 2015-07-13
            • 2022-12-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-09-30
            相关资源
            最近更新 更多