How can I recursively read out directories in Perl?

23,479

Solution 1

This should do the trick

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

Solution 2

You should always use strict and warnings to help you debug your code. Perl would have warned you for example that @files is not declared. But the real problem with your function is that you declare a lexical variable @paths on every recursive call to list_dirs and don't push the return value back after the recursion step.

push @paths, list_dir($eachFile)

If you don't want to install additional modules, the following solution should probably help you:

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

Solution 3

The answer by mdom explains how your initial attempt went astray. I would also suggest that you consider friendlier alternatives to File::Find. CPAN has several options. Here's one.

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

Also see here:

And here is a rewrite of your recursive solution. Things to note: use strict; use warnings; and the use of a scoping block to create a static variable for the subroutine.

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

Solution 4

I think you have problem in the following line in your code

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

You change the $path variable into $rootpath.

It will store the path correctly.

Solution 5

I use this script to remove hidden files (created by Mac OS X) from my USB Pendrive, where I usually use it to listen music in the car, and any file ending with ".mp3", even when it starts with "._", will be listed in the car audio list.

#!/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" ;
  }
}
Share:
23,479
Przemek
Author by

Przemek

Updated on April 26, 2020

Comments

  • Przemek
    Przemek about 4 years

    I want to read out a directory recursively to print the data-structure in an HTML-Page with Template::Toolkit. But I'm hanging in how to save the Paths and Files in a form that can be read our easy.

    My idea started like this

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

    How could I solve this problem?

  • Przemek
    Przemek about 14 years
    with this routine I only get one result, and this is the directory I give the routine to start.
  • mdom
    mdom about 14 years
    Can you show me the code you use to examine this? It's working just fine here. Maybe test it with "use Dumper; print Dumper list_dirs '/home'".
  • ed9w2in6
    ed9w2in6 over 11 years
    so, glob actually doesn't support recursive listing of files, right?
  • Htbaa
    Htbaa over 11 years
    that's correct, it'll only get the files from the given directory.
  • mabalenk
    mabalenk about 3 years
    Can you please explain what happens in the find command? It looks cryptic for a Perl novice.