Finding all Installed Perl Modules

There are a ton of Perl modules available. (See CPAN.) One problem that I've run into from time to time is determining whether I have a specific module installed or not. The most common approach I've used to determine this is the following command:

perl -Mmodule::name -e 1

If the command terminates correctly without errors, then the module is installed.

That's all well and good if you are looking for a specific module. However, there are times when you want to see if you have any modules matching a specific string. (For example, I recently wanted to see if my computer had any IMAP modules installed.)

Since Perl looks for modules under the directories listed in @INC, the simplest approach is to use File::Find with @INC as the list of directories to search. This can be done several ways, depending on your needs. Here are a few that I came up with.

perl -MFile::Find -e 'find(sub {/\.pm$/ && print "$File::Find::name\n"}, @INC);'

The above code has the advantages that it is simple and that it prints out the full path to reach each module (in case you are wondering where it is installed). However, it is also likely to print out duplicates, since some architecture-specific paths are listed under standard paths.

perl -MFile::Find -MConfig -e '$A=$Config{myarchname};find({no_chdir=>1,wanted=>sub{s/\.pm$//||next;s/^$File::Find::topdir[\/\\]*($A[\/\\]*)?//;s/[\/\\]+/::/g;$H{$_}++}}, @INC);print join("\n",sort keys %H)'

The above code prints out a de-duplicated, sorted module list with package names given in the normal "module::name" syntax. Admitedly, it is a little cryptic and compact so that it can still fit easily on most command lines without issues. Here is what it looks like when passed to Deparse:

use File::Find;
use Config;
$A = $Config{'myarchname'};
find({'no_chdir', 1, 'wanted', sub {
next unless s/\.pm$//;
s(^$File::Find::topdir[/\\]*($A[/\\]*)?)[];
s([/\\]+)[::]g;
$H{$_}++;
}
}, @INC);
print join("\n", sort(keys %H));

Note that the code assumes that path names concatenate with either a forward or backward slash (which covers most operating systems out there, including Windows and Unix). If your operating system uses a different delimiter, you will need to change the code appropriately or use the first command (which works on all operating systems).