Как я могу рекурсивно считывать каталоги в Perl? - PullRequest
11 голосов
/ 19 марта 2010

Я хочу рекурсивно прочитать каталог для печати структуры данных на HTML-странице с Template :: Toolkit. Но я пытаюсь сохранить пути и файлы в форме, удобной для чтения.

Моя идея началась так

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 ]

18 голосов
/ 19 марта 2010

Это должно сработать

 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');
8 голосов
/ 19 марта 2010

Вы всегда должны использовать строгие и предупреждения, чтобы помочь вам отладить ваш код. Например, 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;
}
5 голосов
/ 19 марта 2010

Ответ от 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 голосов
/ 19 марта 2010

Я думаю, что у вас есть проблема в следующей строке в вашем коде

for my $eachFile (glob($path.'*'))

Вы меняете переменную $ path на $ rootpath.

Он будет правильно хранить путь.

1 голос
/ 05 октября 2013

Я использую этот сценарий для удаления скрытых файлов (созданных Mac OS X) с моего USB Pendrive, где я обычно использую его для прослушивания музыки в машине, и любой файл, заканчивающийся на «.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" ;
  }
}
0 голосов
/ 25 апреля 2014

вы можете использовать этот метод в качестве рекурсивного поиска файлов, которые разделяют определенные типы файлов,

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...