CJ7
CJ7

Reputation: 23275

How to loop through files in all sub directories?

In perl I can loop through the files in the current directory by doing the following:

foreach $file (<*.*>) {
        print "$file found\n";
        # do stuff
}

How can I do the same thing but to all files in all sub-directories?

Upvotes: 0

Views: 2055

Answers (2)

Borodin
Borodin

Reputation: 126722

I find File::Find::Rule unnecessarily fussy and clumsy, especially for a simple application like this. Ultimately it is just a wrapper for the core module File::Find, and I think the base class itself is a good choice for a straightforward application like yours

File::Find allows you to specify a callback subroutine that will be executed for every node (file or directory) within a specified root directory

By default, that subroutine is called with the following context

  • $File::Find::name is set to the full path to the node
  • $File::Find::dir is set to the path to the directory containing the
  • $_ is set to the name of the node, without its path
  • The current working directory is set to $File::Find::dir

If you want, say, to list all files beneath your current directory, then you would write this. All nodes but plain files are rejected using the -f file test operator, works on $_ and finds the right file because the working directory has been temporarily changed

use strict;
use warnings 'all';

use File::Find 'find';

find(\&wanted, '.');

sub wanted {

    return unless -f;

    print $File::Find::name, "\n";
}

If you prefer, you can use an anonymous subroutine within the call to find. This code does exactly the same thing

find(sub {
    return unless -f;
    print $File::Find::name, "\n";
}, '.');

Upvotes: 0

ikegami
ikegami

Reputation: 385506

File::Find::Rule is a great module for recursively listing files.

All files (as you asked):

use File::Find::Rule qw( );

for my $qfn (File::Find::Rule->in(".")) {
   ...
}

Just the files with "." in their name (as per your example):

use File::Find::Rule qw( );

for my $qfn (File::Find::Rule->name("*.*")->in(".")) {
   ...
}

Adding ->file limits the results to plain files (filtering out directories).

Upvotes: 6

Related Questions