Finding files with Perl
Removing the sub
from sub wanted;
just makes it a call to the wanted
function, not a forward declaration.
However, the wanted
function hasn't been designed to be called directly from your code - it's been designed to be called by File::Find. File::Find does useful stuff like populating$_
before calling it.
There's no need to forward-declare wanted
here, but if you want to remove the forward declaration, remove the whole sub wanted;
line - not just the word sub
.
I'm not a big fan of File::Find. It just doesn't work right. The find
command doesn't return a list of files, so you either have to use a non-local array variable in your find
to capture your list of files you've found (not good), or place your entire program in your wanted subroutine (even worse). Plus, the separate subroutine means that your logic is separate from your find
command. It's just ugly.
What I do is inline my wanted
subroutine inside my find
command. Subroutine stays with the find. Plus, my non-local array variable is now just part of my find
command and doesn't look so bad
Here's how I handle the File::Find
-- assuming I want files that have a .pl
suffix:
my @file_list;
find ( sub {
return unless -f; #Must be a file
return unless /\.pl$/; #Must end with `.pl` suffix
push @file_list, $File::Find::name;
}, $directory );
# At this point, @file_list contains all of the files I found.
This is exactly the same as:
my @file_list;
find ( \&wanted, $directory );
sub wanted {
return unless -f;
return unless /\.pl$/;
push @file_list, $File::Find::name;
}
# At this point, @file_list contains all of the files I found.
In lining just looks nicer. And, it keep my code together. Plus, my non-local array variable doesn't look so freaky.
I also like taking advantage of the shorter syntax in this particular way. Normally, I don't like using the inferred $_
, but in this case, it makes the code much easier to read. My original Wanted is the same as this:
sub wanted {
my $file_name = $_;
if ( -f $file_name and $file_name =~ /\.pl$/ ) {
push @file_list, $File::Find::name;
}
}
File::Find
isn't that tricky to use. You just have to remember:
- When you find a file you don't want, you use
return
to go to the next file. $_
contains the file name without the directory, and you can use that for testing the file.- The file's full name is
$File::Find::name
. - The file's directory is
$File::Find::dir
.
And, the easiest way is to push the files you want into an array, and then use that array later in your program.