Reputation: 31598
Using File::Find, how can I pass parameters to the function that processes each file?
I have a Perl script that traverses directories in order to convert some 3-channel TIFF files to JPEG files (3 JPEG files per TIFF file). This works, but I would like to pass some parameters to the function that processes each file (short of using global variables).
Here is the relevant part of the script where I have tried to pass the parameter:
use File::Find;
sub findFiles
{
my $IsDryRun2 = ${$_[0]}{anInIsDryRun2};
}
find ( { wanted => \&findFiles, anInIsDryRun2 => $isDryRun }, $startDir);
$isDryRun
is a scalar. $startDir
is a string, full path to a directory.
$IsDryRun2
is not set:
Use of uninitialized value $IsDryRun2 in concatenation (.) or string at TIFFconvert.pl line 197 (#1) (W uninitialized) An undefined value was used as if it were already defined. It was interpreted as a "" or a 0, but maybe it was a mistake. To suppress this warning assign a defined value to your variables.
(The old call without parameters was: find ( \&findFiles, $startDir);
)
Test platform (but the production home will be a Linux machine, Ubuntu 9.1, Perl 5.10, 64 bit): ActiveState Perl 64 bit. Windows XP. From perl -v: v5.10.0 built for MSWin32-x64-multi-thread Binary build 1004 [287188] provided by ActiveState.
Upvotes: 13
Views: 6602
Reputation: 5430
#
# -----------------------------------------------------------------------------
# Read directory recursively and return only the files matching the regex
# for the file extension. Example: Get all the .pl or .pm files:
# my $arrRefTxtFiles = $objFH->doReadDirGetFilesByExtension ($dir, 'pl|pm')
# -----------------------------------------------------------------------------
sub doReadDirGetFilesByExtension {
my $self = shift; # Remove this if you are not calling OO style
my $dir = shift;
my $ext = shift;
my @arr_files = ();
# File::find accepts ONLY single function call, without params, hence:
find(wrapp_wanted_call(\&filter_file_with_ext, $ext, \@arr_files), $dir);
return \@arr_files;
}
#
# -----------------------------------------------------------------------------
# Return only the file with the passed extensions
# -----------------------------------------------------------------------------
sub filter_file_with_ext {
my $ext = shift;
my $arr_ref_files = shift;
my $F = $File::Find::name;
# Fill into the array behind the array reference any file matching
# the ext regex.
push @$arr_ref_files, $F if (-f $F and $F =~ /^.*\.$ext$/);
}
#
# -----------------------------------------------------------------------------
# The wrapper around the wanted function
# -----------------------------------------------------------------------------
sub wrapp_wanted_call {
my ($function, $param1, $param2) = @_;
sub {
$function->($param1, $param2);
}
}
Upvotes: 0
Reputation: 4318
See the PerlMonks entry Why I hate File::Find and how I (hope I) fixed it describing how to do it with closures.
Upvotes: 3
Reputation: 132802
You can create any sort of code reference you like. You don't have to use a reference to a named subroutine. For many examples of how to do this, see my File::Find::Closures module. I created that module to answer precisely this question.
Upvotes: 3
Reputation: 239861
You need to create a sub reference that calls your wanted sub with the desired parameters:
find(
sub {
findFiles({ anInIsDryRun2 => $isDryRun });
},
$startDir
);
This is, more-or-less, currying. It's just not pretty currying. :)
Upvotes: 16