How do I read in the contents of a directory in Perl?

How do I get Perl to read the contents of a given directory into an array?

Backticks can do it, but is there some method using 'scandir' or a similar term?


Solution 1:

opendir(D, "/path/to/directory") || die "Can't open directory: $!\n";
while (my $f = readdir(D)) {
    print "\$f = $f\n";
}
closedir(D);

EDIT: Oh, sorry, missed the "into an array" part:

my $d = shift;

opendir(D, "$d") || die "Can't open directory $d: $!\n";
my @list = readdir(D);
closedir(D);

foreach my $f (@list) {
    print "\$f = $f\n";
}

EDIT2: Most of the other answers are valid, but I wanted to comment on this answer specifically, in which this solution is offered:

opendir(DIR, $somedir) || die "Can't open directory $somedir: $!";
@dots = grep { (!/^\./) && -f "$somedir/$_" } readdir(DIR);
closedir DIR;

First, to document what it's doing since the poster didn't: it's passing the returned list from readdir() through a grep() that only returns those values that are files (as opposed to directories, devices, named pipes, etc.) and that do not begin with a dot (which makes the list name @dots misleading, but that's due to the change he made when copying it over from the readdir() documentation). Since it limits the contents of the directory it returns, I don't think it's technically a correct answer to this question, but it illustrates a common idiom used to filter filenames in Perl, and I thought it would be valuable to document. Another example seen a lot is:

@list = grep !/^\.\.?$/, readdir(D);

This snippet reads all contents from the directory handle D except '.' and '..', since those are very rarely desired to be used in the listing.

Solution 2:

A quick and dirty solution is to use glob

@files = glob ('/path/to/dir/*');

Solution 3:

This will do it, in one line (note the '*' wildcard at the end)

@files = </path/to/directory/*>;
# To demonstrate:
print join(", ", @files);

Solution 4:

IO::Dir is nice and provides a tied hash interface as well.

From the perldoc:

use IO::Dir;
$d = IO::Dir->new(".");
if (defined $d) {
    while (defined($_ = $d->read)) { something($_); }
    $d->rewind;
    while (defined($_ = $d->read)) { something_else($_); }
    undef $d;
}

tie %dir, 'IO::Dir', ".";
foreach (keys %dir) {
    print $_, " " , $dir{$_}->size,"\n";
}

So you could do something like:

tie %dir, 'IO::Dir', $directory_name;
my @dirs = keys %dir;

Solution 5:

You could use DirHandle:

use DirHandle;
$d = new DirHandle ".";
if (defined $d)
{
    while (defined($_ = $d->read)) { something($_); }
    $d->rewind;
    while (defined($_ = $d->read)) { something_else($_); }
    undef $d;
}

DirHandle provides an alternative, cleaner interface to the opendir(), closedir(), readdir(), and rewinddir() functions.