2

[Perl] Finding Files, The Fun And Elegant Way


Posted by Artem Russakovskii on April 8th, 2009 in Awesomeness, Linux, Perl, Programming, Tutorials

Updated: October 6th, 2009

No matter what programming language you use, there comes a time when you need to search for a file somewhere on the file system. Here, I want to talk about accomplishing this task in Perl. There are many ways of doing so, most of them boring, but I want to discuss the fun and elegant way – using File::Find::Rule.

Let me briefly discuss some of the other methods first.

Limited

Using glob() (or <>, TODO verify) you can find files in a single directory, using only the limited shell wildcard support. For example,

1
my @files = glob(&quot;tmp*&quot;);

I prefer glob() to <> because glob()'s parameters can be more than just text (for ex functions) while <> treats everything inside as text.

Boring

File::Find is the de facto standard for searching in Perl.

This method finds files that end in .pl in "." and "../SomeDir", following symlinks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/perl -w
 
use File::Find;
use Data::Dumper;
use File::Basename;
my @directories_to_search = (&quot;.&quot;, &quot;../SomeDir&quot;);
my @file_list = ();
 
find(
  { wanted =&gt;
    sub {
      if ( basename($File::Find::name) =~ /\.pl$/i )
      { 
        push @file_list, $File::Find::name;
      }
    },
    follow =&gt; 1
  },
  @directories_to_search
);
print Dumper @file_list;

It works fine, except it's horribly ugly and boring. Let's have a look at something more fun.

The Fun And Elegant Way

File::Find::Rule. Just have a look at this beauty.

Just like above, find all .pl files in "." and "../SomeDir", following symlinks:

1
2
print Dumper (File::Find::Rule-&gt;name(&quot;*.pl&quot;)-&gt;file-&gt;extras({ follow =&gt; 1 })-&gt;
in(&quot;.&quot;, &quot;../SomeDir&quot;));

Same as above, except bypass .svn directories (shaves off a ton of time with a lot of directories):

1
2
print Dumper (File::Find::Rule-&gt;not(File::Find::Rule-&gt;directory-&gt;name('.svn')-&gt;
prune-&gt;discard)-&gt;name(&quot;*.pl&quot;)-&gt;file-&gt;extras({ follow =&gt; 1 })-&gt;in(&quot;.&quot;, &quot;../SomeDir&quot;));

Find all .log files that are older than 24 hours in "."

1
2
3
my $epoch_time_1_day_ago = time() - 60*60*24;
print Dumper (File::Find::Rule-&gt;file-&gt;name(&quot;*.log&quot;)-&gt;
mtime(&quot;&lt;$epoch_time_1_day_ago&quot;)-&gt;in('.'));

Be sure to read the File::Find::Rule perldoc for more options and remember: have fun with your code!

Thanks to Perlbuzz and Andy Lester for pointing me to this library a few months ago.

● ● ●
Artem Russakovskii is a San Francisco programmer and blogger. Follow Artem on Twitter (@ArtemR) or subscribe to the RSS feed.

In the meantime, if you found this article useful, feel free to buy me a cup of coffee below.