perl.gg / snippets

Io All Recursion

2024-07-11

This page shows how to use the IO::All module to search through directories and subdirectories recursively. The trick lies in a single capital letter that changes how the search behaves.

Part 1: THE CAPITAL LETTER THAT CHANGES EVERYTHING

The difference between recursive and non-recursive search comes down to capitalization.
All_Files # Recursive - goes into subdirectories all_files # Non-recursive - current directory only
You will likely miss this detail at first, and you will spend time debugging a search that only checks the top folder. The capital letter controls whether the module walks into subdirectories.

Part 2: THE VERBOSE APPROACH

We can start with the straightforward version that is easy to read and modify later.
use IO::All; my $dir = '/path/to/search'; my @files = io($dir)->All_Files; foreach my $file (@files) { print $file->name, "\n"; }
The io() function wraps a directory path into an IO::All object. The All_Files method then walks every subdirectory and returns a flat list of the files it finds.

Every entry in that list is an IO::All object, which means you can call methods like ->name, ->size, or ->mtime directly on it.

Part 3: THE CONCISE ONE-LINER

You can compress that same logic into a single line when you need a quick filter.
use IO::All; my @indexes = grep { $_->filename eq 'index.html' } io($dir)->All_Files;
That is enough code to run the search. We use grep to filter the recursive file list, and ->filename returns just the file name without the surrounding path.

You can also run an action on each match right inside the filter.

print $_->name, "\n" for grep { $_->filename eq 'index.html' } io($dir)->All_Files;

Part 4: USEFUL METHODS ON FILE OBJECTS

Every file object you get back carries a set of built-in methods for inspection.
$file->name # Full path: /path/to/file.txt $file->filename # Just the name: file.txt $file->size # Size in bytes $file->mtime # Modification time (epoch) $file->ext # Extension: txt $file->slurp # Read entire contents $file->dir # Parent directory as IO::All object
You can combine those methods to filter by type and size in one statement.
my @big_perl = grep { $_->ext eq 'pl' && $_->size > 1024 } io($dir)->All_Files;

Part 5: WORKING WITH DIRECTORIES TOO

You can ask the same methods to return directories alongside files.
my @everything = io($dir)->All; # Files AND directories my @dirs_only = io($dir)->All_Dirs; # Just directories
The lowercase versions (all, all_files, all_dirs) do the same thing but without recursion, meaning they only list the immediate contents of the starting folder.

Part 6: A PRACTICAL EXAMPLE

Here is a complete script that finds every Perl file in a tree and tallies their line counts.
#!/usr/bin/perl use strict; use warnings; use IO::All; my $dir = shift || '.'; my $total_lines = 0; for my $file (grep { $_->ext =~ /^p[lm]$/ } io($dir)->All_Files) { my @lines = $file->slurp; my $count = scalar @lines; $total_lines += $count; printf "%6d %s\n", $count, $file->name; } print "-" x 40, "\n"; printf "%6d TOTAL\n", $total_lines;
This script finds all .pl and .pm files, counts their lines, and prints a summary. The regex /^p[lm]$/ matches either pl or pm, which covers both standalone scripts and Perl modules.

Part 7: REMEMBER THE CAPITAL A

I will repeat the rule one more time because it controls whether your search actually goes deep.
All_Files # RECURSIVE - this is probably what you want all_files # not recursive - just current directory
The capital letter is what turns a shallow scan into a full directory dive.

IO::All turns what would otherwise be twenty lines of opendir, readdir, and manual recursion into compact one-liners. You will likely find yourself reaching for it whenever a directory tree needs inspection.

Happy file hunting!

perl.gg