I/O

readdir#

Read the next entry, or all remaining entries, from a directory handle opened by opendir.

readdir is the directory counterpart of readline: it pulls names out of a directory handle one at a time in scalar context, or all at once in list context. The handle must already have been opened with opendir; iteration advances a position that rewinddir, seekdir, and telldir can manipulate.

Synopsis#

readdir DIRHANDLE
my $name  = readdir $dh;
my @names = readdir $dh;
while (readdir $dh) { ... }     # sets $_

What you get back#

Context-dependent:

  • Scalar context: the next entry’s name as a string, or undef when the directory is exhausted.

  • List context: every remaining entry as a list of strings, or the empty list when the directory is already exhausted.

Entries are bare filenames, not paths. readdir returns "foo.txt", never "/some/dir/foo.txt". If you plan to hand the result to a file test, open, stat, or any other call that resolves paths against the current working directory, prepend the directory yourself — readdir does not chdir into the directory it is reading.

The list always includes the entries . (current directory) and .. (parent directory) as reported by the underlying filesystem. Filter them out explicitly if you do not want them:

my @real = grep { $_ ne '.' && $_ ne '..' } readdir $dh;

Order is filesystem-dependent, not alphabetical. ext4, XFS, tmpfs, NFS, and FAT each return entries in their own internal order, which may be insertion order, hash order, or something else entirely. Never assume sorted output. If you need a predictable order, sort the result:

my @names = sort readdir $dh;

Examples#

Read every name into a list, drop the dot entries, and sort:

opendir(my $dh, $some_dir) or die "opendir $some_dir: $!";
my @names = sort grep { !/^\.\.?\z/ } readdir $dh;
closedir $dh;

Iterate one entry at a time. A bare readdir in a while condition assigns to $_ and tests the result for definedness, not truth — so an entry literally named "0" still keeps the loop running:

opendir(my $dh, $some_dir) or die "opendir $some_dir: $!";
while (readdir $dh) {
    print "$some_dir/$_\n";
}
closedir $dh;

Filetest with the directory prepended — forgetting the prefix is the classic readdir bug:

opendir(my $dh, $some_dir) or die "opendir $some_dir: $!";
my @dotfiles = grep { /^\./ && -f "$some_dir/$_" } readdir $dh;
closedir $dh;

Scalar context — one name per call, undef signals end of directory:

opendir(my $dh, $some_dir) or die "opendir $some_dir: $!";
while (defined(my $name = readdir $dh)) {
    next if $name eq '.' || $name eq '..';
    process("$some_dir/$name");
}
closedir $dh;

Rewind and read a second time — the handle stays open and usable:

my @first  = readdir $dh;
rewinddir $dh;
my @second = readdir $dh;   # same entries, possibly different order

Edge cases#

  • Exhausted handle: further calls return undef in scalar context, empty list in list context. Use rewinddir to start over.

  • Closed or invalid handle: returns undef (scalar) or empty list (list) and sets $!. Under use warnings Perl emits readdir() attempted on invalid dirhandle.

  • Definedness test in while: both while (readdir $dh) and while (my $n = readdir $dh) (and their for equivalents) are special-cased to test defined, not truth. An entry named "0" is returned and the loop continues.

  • . and .. are always present on POSIX filesystems, even in an otherwise empty directory. Filter them if you want only real content.

  • No path prefix: entries are bare names. Any filetest or open on the raw return value tests relative to the current working directory, not $some_dir.

  • No sorting: the order is whatever the kernel returns. Apply sort explicitly if stability matters.

  • Concurrent directory changes: entries added or removed during iteration may or may not appear, per the platform. The only safe assumption is that entries present at opendir time and not removed will be reported.

  • Encoding: readdir returns byte strings as the kernel stores them. On a filesystem using UTF-8 filenames, apply Encode::decode_utf8 or configure the open pragma if you need character strings.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • opendir — opens the directory handle that readdir reads from; always the first call in the sequence

  • closedir — releases the handle once iteration is done

  • rewinddir — resets the iteration position to the start of the directory

  • seekdir — jumps to a previously recorded position

  • telldir — records the current position for later seekdir

  • glob — shell-style pattern matching over directory contents; higher-level when you want *.txt rather than every entry