I'm a bit confused from File::Find
documentation... What is the equivalent to $ find my_dir -maxdepth 2 -name "*.txt"
?

- 30,738
- 21
- 105
- 131

- 29,258
- 50
- 133
- 186
-
`my @files = \`find $my_dir -maxdepth 2 -name *.txt\`;`... I don't get the `Wanted` sub. Can't I just give a regex? – David B Sep 25 '10 at 21:07
-
Another question about [Finding files with Perl](http://stackoverflow.com/questions/17754931/finding-files-with-perl) mentions some alternatives not mentioned in the answers below. – G. Cito Jan 05 '15 at 15:00
4 Answers
Personally, I prefer File::Find::Rule
as this doesn't need you to create callback routines.
use strict;
use Data::Dumper;
use File::Find::Rule;
my $dir = shift;
my $level = shift // 2;
my @files = File::Find::Rule->file()
->name("*.txt")
->maxdepth($level)
->in($dir);
print Dumper(\@files);
Or alternatively create an iterator:
my $ffr_obj = File::Find::Rule->file()
->name("*.txt")
->maxdepth($level)
->start($dir);
while (my $file = $ffr_obj->match())
{
print "$file\n"
}

- 30,738
- 21
- 105
- 131

- 3,601
- 4
- 22
- 37
-
+1 I think this is the simplest, most `$ find` -like solution suggested. – David B Sep 28 '10 at 15:17
-
unfortunately with iterator, it fetches all directory structure into memory. when structure is so big (typical), then process will consume a lot of memory. Its why this resolution is often not good. In opposite, scannind dir tree by system find command gives option for fetching it online without consuming big amount of RAM. – Znik Feb 02 '18 at 13:46
I think I'd just use a glob
since you really don't need all the directory traversal stuff:
my @files = glob( '*.txt */*.txt' );
I made File::Find::Closures to make it easy for you to create the callbacks that you pass to find
:
use File::Find::Closures qw( find_by_regex );
use File::Find qw( find );
my( $wanted, $reporter ) = File::Find::Closures::find_by_regex( qr/\.txt\z/ );
find( $wanted, @dirs );
my @files = $reporter->();
Normally, you can turn a find(1) command into a Perl program with find2perl
(removed in v5.20 but on CPAN):
% find2perl my_dir -d 2 -name "*.txt"
But apparently find2perl
doesn't understand -maxdepth
, so you could leave that off:
% find2perl my_dir -name "*.txt"
#! /usr/local/perls/perl-5.13.5/bin/perl5.13.5 -w
eval 'exec /usr/local/perls/perl-5.13.5/bin/perl5.13.5 -S $0 ${1+"$@"}'
if 0; #$running_under_some_shell
use strict;
use File::Find ();
# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.
# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name = *File::Find::name;
*dir = *File::Find::dir;
*prune = *File::Find::prune;
sub wanted;
# Traverse desired filesystems
File::Find::find({wanted => \&wanted}, 'my_dir');
exit;
sub wanted {
/^.*\.txt\z/s
&& print("$name\n");
}
Now that you have the starting programming, you can plug in whatever else you need, including a preprocess
step to prune the tree.

- 129,424
- 31
- 207
- 592
use File::Find ;
use Cwd ;
my $currentWorkingDir = getcwd;
my @filesToRun = ();
my $filePattern = '*.cmd' ;
#add only files of type filePattern recursively from the $currentWorkingDir
find( sub { push @filesToRun, $File::Find::name
if ( m/^(.*)$filePattern$/ ) }, $currentWorkingDir) ;
foreach my $file ( @filesToRun )
{
print "$file\n" ;
}

- 129,424
- 31
- 207
- 592

- 5,114
- 1
- 56
- 53
There's also the handy find2perl utility. Use it instead of the Unix find command, with the same command-line arguments as 'find', and it will generate the corresponding Perl code that makes use of File::Find.
$ find2perl my_dir -maxdepth 2 -name "*.txt"

- 30,738
- 21
- 105
- 131

- 2,181
- 2
- 17
- 14