You want to do something to each file in a particular directory.
Use
opendir
to open the directory and then
readdir
to retrieve every filename:
opendir(DIR, $dirname) or die "can't opendir $dirname: $!"; while (defined($file = readdir(DIR))) { # do something with "$dirname/$file" } closedir(DIR);
The
opendir
,
readdir
, and
closedir
functions operate on directories as
open
, < >, and
close
operate on files. Both use handles, but the directory handles used by
opendir
and friends are different from the file handles used by
open
and friends. In particular, you can't use < > on a directory handle.
In scalar context,
readdir
returns the next filename in the directory until it reaches the end of the directory when it returns
undef
. In list context it returns the rest of the filenames in the directory or an empty list if there were no files left. As explained in the Introduction, the filenames returned by
readdir
do not include the directory name. When you work with the filenames returned by
readdir
, you must either move to the right directory first or prepend the directory to the filename.
This shows one way of prepending:
$dir = "/usr/local/bin"; print "Text files in $dir are:\n"; opendir(BIN, $dir) or die "Can't open $dir: $!"; while( defined ($file = readdir BIN) ) { print "$file\n" if -T "$dir/$file"; } closedir(BIN);
We test
$file
with
defined
because simply saying
while
($file
=
readdir
BIN)
would only be testing truth and not definedness. Although the loop would end when
readdir
ran out of files to return, it would also end prematurely if a file had the name "
0"
.
The
readdir
function will return the special directories
"."
(the directory itself) and
".."
(the parent of the directory). Most people skip the files with code like:
while ( defined ($file = readdir BIN) ) { next if $file =~ /^\.\.?$/; # skip . and .. # ... }
Like filehandles, directory handles are per-package constructs. Further, you have two ways of getting a local
directory handle: use
local
*DIRHANDLE
or use an object module (see
Recipe 7.16
). The appropriate module in this case is
DirHandle
. The following code uses DirHandle and produces a sorted list of plain files that aren't dotfiles (that is, whose names don't begin with a
"."
):
use DirHandle; sub plainfiles { my $dir = shift; my $dh = DirHandle->new($dir) or die "can't opendir $dir: $!"; return sort # sort pathnames grep { -f } # choose only "plain" files map { "$dir/$_" } # create full paths grep { !/^\./ } # filter out dot files $dh->
read()
; # read all entries }
DirHandle's
read
method behaves just like
readdir
, returning the rest of the filenames. The bottom
grep
only returns those that don't begin with a period. The
map
turns the filenames returned by
read
into fully qualified filenames, and the top
grep
filters out directories, links, etc. The resulting list is then
sort
ed and returned.
In addition to
readdir
, there's also
rewinddir
(to move the directory handle back to the start of the filename list),
seekdir
(to move to a specific offset in the list), and
telldir
(to find out how far from the start of the list you are).
The
closedir
,
opendir
,
readdir
,
rewinddir
,
seekdir
, and
telldir
functions in
perlfunc
(1) and in
Chapter 3
of
Programming Perl
; documentation for the standard DirHandle module (also in
Chapter 7
of
Programming Perl
)
9.4. Recognizing Two Names for the Same File | 9.6. Globbing, or Getting a List of Filenames Matching a Pattern |