72

Is there a function in Perl that lists all the files and directories in a directory? I remember that Java has the File.list() to do this? Is there a comparable method in Perl?

ScottJShea
  • 7,041
  • 11
  • 44
  • 67
Paradius
  • 7,949
  • 11
  • 32
  • 38

6 Answers6

106

If you want to get content of given directory, and only it (i.e. no subdirectories), the best way is to use opendir/readdir/closedir:

opendir my $dir, "/some/path" or die "Cannot open directory: $!";
my @files = readdir $dir;
closedir $dir;

You can also use:

my @files = glob( $dir . '/*' );

But in my opinion it is not as good - mostly because glob is quite complex thing (can filter results automatically) and using it to get all elements of directory seems as a too simple task.

On the other hand, if you need to get content from all of the directories and subdirectories, there is basically one standard solution:

use File::Find;

my @content;
find( \&wanted, '/some/path');
do_something_with( @content );

exit;

sub wanted {
  push @content, $File::Find::name;
  return;
}
  • 4
    I always forget that readdir just returns a list of relative filenames, not the entire path! – Matthew Lock Aug 04 '14 at 07:15
  • 1
    Thanks for discouraging the use of globbing for this task. Another downside of using globbing for this is, that it will not find hidden files (those starting with a dot). – josch Dec 22 '16 at 16:12
15

this should do it.

my $dir = "bla/bla/upload";
opendir DIR,$dir;
my @dir = readdir(DIR);
close DIR;
foreach(@dir){
    if (-f $dir . "/" . $_ ){
        print $_,"   : file\n";
    }elsif(-d $dir . "/" . $_){
        print $_,"   : folder\n";
    }else{
        print $_,"   : other\n";
    }
}
Matthew Vines
  • 27,253
  • 7
  • 76
  • 97
  • 1
    You should check opendir for failure (opendir...or die "Error message: $!"). Also, am I missing something? What is Win32::GUI::DoEvents() doing here? (I don't see anything relevant in the question.) – Telemachus Jun 25 '09 at 21:33
  • this is the best way i dont want or wish to remember regular expresions for something that should be easy to do, i will use this to create a function like list($dir,"f"); for files "d" for directory, thanks for posting this – Geomorillo Mar 03 '14 at 06:41
14

readdir() does that.

Check http://perldoc.perl.org/functions/readdir.html

opendir(DIR, $some_dir) || die "can't opendir $some_dir: $!";
@dots = grep { /^\./ && -f "$some_dir/$_" } readdir(DIR);
closedir DIR;
Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
11

Or File::Find

use File::Find;
finddepth(\&wanted, '/some/path/to/dir');
sub wanted { print };

It'll go through subdirectories if they exist.

Todd Gardner
  • 13,313
  • 39
  • 51
5

If you are a slacker like me you might like to use the File::Slurp module. The read_dir function will reads directory contents into an array, removes the dots, and if needed prefix the files returned with the dir for absolute paths

my @paths = read_dir( '/path/to/dir', prefix => 1 ) ;
Matthew Lock
  • 13,144
  • 12
  • 92
  • 130
3

This will list Everything (including sub directories) from the directory you specify, in order, and with the attributes. I have spent days looking for something to do this, and I took parts from this entire discussion, and a little of my own, and put it together. ENJOY!!

#!/usr/bin/perl --
print qq~Content-type: text/html\n\n~;
print qq~<font face="arial" size="2">~;

use File::Find;

# find( \&wanted_tom, '/home/thomas/public_html'); # if you want just one website, uncomment this, and comment out the next line
find( \&wanted_tom, '/home');
exit;

sub wanted_tom {
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat ($_);
$mode = (stat($_))[2];
$mode = substr(sprintf("%03lo", $mode), -3);

if (-d $File::Find::name) {
print "<br><b>--DIR $File::Find::name --ATTR:$mode</b><br>";
 } else {
print "$File::Find::name --ATTR:$mode<br>";
 }
  return;
}