2010-03-19 16 views
10

Quiero leer un directorio recursivamente para imprimir la estructura de datos en una página HTML con Template :: Toolkit. Pero estoy explicando cómo guardar las rutas y los archivos en una forma que se puede leer fácilmente.¿Cómo puedo leer recursivamente directorios en Perl?

Mi idea comenzó así

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; 
} 

¿Cómo podría solucionar este problema?

Respuesta

18

Esto debería hacer el truco

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'); 
+0

por lo tanto, glob en realidad no es compatible con la lista recursiva de archivos, ¿verdad? –

+0

eso es correcto, solo obtendrá los archivos del directorio dado. – Htbaa

8

Siempre debe utilizar estrictas y advertencias para ayudarlo a depurar su código. Perl te habría advertido, por ejemplo, que @files no está declarado. Pero el verdadero problema con su función es que declara una variable léxica @paths en cada llamada recursiva al list_dirs y no vuelve a presionar el valor de retorno después del paso de recursión.

push @paths, list_dir($eachFile) 

Si no desea instalar módulos adicionales, la siguiente solución debe probablemente le ayudará a:

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; 
} 
+0

con esta rutina solo me dan un resultado, y este es el directorio Doy la rutina para empezar. – Przemek

+0

¿Puede mostrarme el código que utiliza para examinar esto? Está funcionando bien aquí. Tal vez probarlo con "use Dumper; print Dumper list_dirs '/ home'". – mdom

3

yo creo que hay un problema en la siguiente línea en su código

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

Cambia la variable $ path a $ rootpath.

Almacenará la ruta correctamente.

5

La respuesta por mdom explica cómo su intento inicial fue por mal camino. También le sugiero que considere alternativas más amigables al File::Find. CPAN tiene varias opciones. Aquí hay uno.

use strict; 
use warnings; 
use File::Find::Rule; 
my @paths = File::Find::Rule->in(@ARGV); 

también ver aquí:

  • SO answer proporcionar CPAN alternativas para File::Find.

  • SO question en los iteradores de directorios.

Y aquí hay una reescritura de su solución recursiva. Cosas a tener en cuenta: use strict; use warnings; y el uso de un bloque de alcance para crear una variable estática para la subrutina.

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; 
    } 
} 
1

Puedo usar este script para eliminar los archivos ocultos (creado por Mac OS X) de mi USB Pendrive, donde suelo utilizarlo para escuchar música en el coche, y cualquier archivo que termina en" .mp3" , incluso cuando comienza con "._", aparecerá en la lista de audio del automóvil.

#!/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

puede utilizar este método como búsqueda de archivos recursiva que separan los tipos de archivo específicos,

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; 
} 
Cuestiones relacionadas