Category: Utility Scripts
Author/Contact Info Clif Bratcher -> cebratcher at gmail dot com
Description: I've been having problems with some cpan installs. You know the deal. They install and test correctly, but something just doesn't work right. *cough* Needs more testing! *cough*

So, in my haste to track down a few of these bugs, I wanted to know where the module(s) were stored. I threw together an extremely simple, but rather useful little script. (It was originally a one-liner, hence the anon sub and the speedy ternary conditional.)

It's definately not fancy, but it does its job gracefully.

IMO It's pretty self explanitory, but the jist is that it does a simple ignore-case regex over all dirs and subdirs in @INC. When it gets a hit, it spits it out.

(Edited to clean up formatting!)
#!/usr/bin/perl 

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

if(my $m = shift){
    find(
        sub{
            /$m/i ? print"$File::Find::name\n" : 0
        },
        @INC);
    }
else {
    print "Please enter a single search string as an argument!\n";
}
Replies are listed 'Best First'.
Re: Module Finder
by blazar (Canon) on Oct 18, 2006 at 16:56 UTC

    But then you have to do the Module to Module-partial-path yourself, mentally. Not that hard, indeed. And one may actually prefer it that way. I wouldn't. However what's more important is that you're transversing all @INC recursively whereas you already know the potential locations for the wanted package. Also suppose you want to find the location of That::Particular::Foo. With your method unless I'm missing something, you're bound to search for 'Foo', and with your match you'll also get not only That::Other::Foo, but also That::Particular::eFoOZ. Last, there are indeed case insensitive (but case preserving) fs'es in widespread use, however case does matter for [Pp]erl, so I would most definitely avoid /i.

    I would proceed like thus instead:

    #!/usr/bin/perl use strict; use warnings; use File::Spec::Functions; die "Usage: $0 <module> [<modules>]\n" unless @ARGV; ($\,$,)=("\n")x2; for my $mod (@ARGV) { print "Searching for `$mod':"; $mod =~ s{::}{/}g; $mod .= '.pm'; my @results=grep -f, map {catfile $_, $mod} @INC; warn "`$mod' not found\n" and next unless @results; print @results, ''; } __END__

    Of course if you don't mind your particular module being actually loaded, and you generally shouldn't care, then you may ask perl to tell you where it found it, inspecting %INC:

    C:\temp>perl -MFile::Find -le "print $INC{'File/Find.pm'}" C:/Programmi/Perl/lib/File/Find.pm

      If you have perldoc available on your system (some sysadmins refuse to install it), it's as easy as:

      on AIX:

      $ perldoc -l File::Find /usr/opt/perl5/lib/5.8.2/File/Find.pm
      or on Windows (returning backslashes):
      C:\>perldoc -l File::Find C:\Perl\lib\File\Find.pm

        That's definately a good way to find a module, but if I don't know the root or branches, it does me no good...
      Yep, the case insensitivity was completely intended. Mainly for those odd instances like Xbase and XBase. I guess, to make it a bit more robust, I should have tossed an argument parser to allow that option to be turned on/off.


      Truthfully, this came about when I was working on a system that had no net connection, but I couldn't remember the root of the MD5 module. (Moronic, I know, but I hadn't used it in a loooong time.)

      With this, it returns what I wanted (Digest::MD5), along with any other MD5 related modules. Given, they may not be very closely related, but I could toss the info into perldoc and find out.


      Thanks for the tips though!

      -inno