file-io advanced

How to use File::Find to recursively search directories in Perl?

Question

How to use File::Find to recursively search directories in Perl?

File::Find is a core Perl module designed for recursively traversing directory trees. It allows you to process every file and directory under a given root path by calling a user-defined subroutine for each entry found. This makes it especially useful for tasks like searching for specific files, gathering information, or performing bulk operations on file systems.

How File::Find Works

The key function in File::Find is find(). You provide it a callback and a starting directory (or directories). It recursively descends into all subdirectories and invokes your callback for each file or directory found. Your callback can then inspect or act on the current item.

The module automates the directory traversal logic, and you get the current entry's name in the global variable $File::Find::name, which is the full path, and the name relative to the current directory in $_. This is typical Perl context handling: $_ is localized in the callback to the basename of the current file/directory.

Basic Syntax

  • find(\&wanted, $directory): Calls &wanted on each file/dir recursively under $directory.
  • Inside &wanted, $_ is the current filename (not full path).
  • $File::Find::name is the full path of the current item.

Example: Recursively Find All .pl Files

use strict;
use warnings;
use File::Find;

# Callback run for each file/dir found
sub wanted {
    # We want only files ending with .pl
    if (-f $_ and $_ =~ /\.pl$/) {
        print "Found Perl script: $File::Find::name\n";
    }
}

my $start_dir = '.';

# Start the recursive search at $start_dir
find(\&wanted, $start_dir);

This script recursively searches from the current directory, printing the full path of every file ending in .pl.

Explanation of Perl Concepts

  • Sigils: $ for scalars ($_, $File::Find::name) and & for subroutine references (&wanted or \&wanted).
  • Context: File::Find localizes $_ for each file name in the callback, so you naturally work on it as the current entry's basename.
  • TMTOWTDI: Perl offers various ways to express recursion or file searching; File::Find is classic and efficient for this.

Common Pitfalls

  • $_ only contains the basename, so do not assume it is the full path.
  • The full path is always in $File::Find::name. Use this when opening files or printing paths.
  • File::Find changes your working directory (chdir) under the hood to optimize calls - if you call other functions within your callback that rely on cwd, be cautious.
  • The order of traversal is undefined; do not rely on a specific order.
  • The find function expects at least one directory argument or arrayref. Passing nothing will cause errors.

Additional Tips

  • You can pass multiple start directories as an array reference to find().
  • Starting with Perl 5.10+, you can use the File::Find::finddepth() function for post-order traversal (visit children before parents).
  • To skip a directory subtree, use $File::Find::prune = 1; inside your wanted subroutine.

Using File::Find is an elegant, efficient way to recursively scan directories in Perl without manually managing recursion or directory handles.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 571ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
(empty)
STDERR
Can't cd to (./) EXPR: Permission denied
 at - line 16.

Was this helpful?

Related Questions