1. Perl
  2. Module
  3. here

File::Find - Recursively process subdirectories

You can use File::Find to process all files recursively.

use File::Find;
find(\&process, $top_dir);

sub process {
  # What you want to do
}

File::Find is chdir, which processes all files while changing directories. Pass a reference to the subroutine as the first argument. (& process is a subroutine and the\symbol creates a reference.)

After the second argument, pass the list of directories you want to process. (In the example, only one). You can change the scan order by using finddepth instead of find. (Explanation below)

If you do not want to change the current directory

If you want to scan without changing the current directory, you can use the "no_chdir" option.

In this case, specify "wanted" as the reference to the subroutine.

find({wanted => \&process, no_chdir => 1}, $top_dir);

Variable that can be used in the processing description

Current current directory $File::Find::dir
Current file name (base name) $_
Current file name (absolute path) $File::Find::name

In the sub process, you can get the current directory and the file name to be processed. Use these to describe what you want to do in each file.

Find scan order (going order)

(1) $top_dir |-(2) top.txt
             |
             |-(3) dir1 |-(4) 1.txt
             | |-(5) dir1_1 |-(6) 1_1.txt
             | |-(7) dir1_2 |-(8) 1_2.txt
             |
             |-(8) dir2 |-(9) 2.txt

Scan in what is commonly referred to as the destination order. In the case of the same hierarchy, files are processed before the directory. (2) comes before (3).

Finddepth scanning order (returning order)

(10) $top_dir |-(1) top.txt
              |
              |-(7) dir1 |-(2) 1.txt
              | |-(4) dir1_1 |-(3) 1_1.txt
              | |-(6) dir1_2 |-(5) 1_2.txt
              |
              |-(9) dir2 |-(8) 2.txt

Scan in what is commonly referred to as the return order. Each directory is processed immediately after all the processing in the hierarchy below it is completed. In the case of the same hierarchy, files are processed before the directory.

Example

This is an example that recursively processes all files.

use strict;
use warnings;
use File::Path;
use Fcntl;
use File::Find;

# Process all files recursively.

# Create directories and files
my $top_dir = "dir_20080530_$$";
my @dirs = (
  "$top_dir/dir1", "$top_dir/dir1/dir1_1", "$top_dir/dir1/dir1_2",
  "$top_dir/dir2",
);
for my $dir (@dirs) {
  eval {mkpath $dir};
  if (@!) {die "@!"}
}

my @files = (
  "$top_dir/top.txt", "$top_dir/dir1/1.txt",
  "$top_dir/dir1/dir1_1/1_1.txt", "$top_dir/dir1/dir1_2/1_2.txt",
  "$top_dir/dir2/2.txt"
);
for my $file (@files) {
  sysopen(my $fh, $file, O_WRONLY | O_CREAT | O_EXCL)
    or die "Unable to create $file .:$!";
  close $fh;
}
print "Preparation: $top_dir has been created.\n\n";

# File::Find example

print "1: Recursively print all file names (base names).\n";
# In the first argument, write the processing you want to do for each file
# Pass a reference to the subroutine.
find(\&print_file_name, $top_dir);
                                     
sub print_file_name {
  # In $_, the directory you are currently scanning
  # The file name used as the base point is stored.
  # $File::Find::dir is currently scanning
  # The directory name is stored.
  print "$_ ($File::Find::dir)\n";
}
print "\n";

print "2: Recursively print all file names (full path).\n";
find(\&print_file_full_name, $top_dir);

sub print_file_full_name {
  # In $_, the directory you are currently scanning
  # The file name used as the base point is stored.
  print $File::Find::name, "\n";
}
print "\n";

print "3: Scan directories in return order\n";
finddepth (\&print_file_full_name, $top_dir);

Output

Preparation: You have created dir_20080530_4944.

1: Recursively output all file names (base names).
. (dir_20080530_4944)
top.txt (dir_20080530_4944)
dir1 (dir_20080530_4944)
1.txt (dir_20080530_4944/dir1)
dir1_1 (dir_20080530_4944/dir1)
1_1.txt (dir_20080530_4944/dir1/dir1_1)
dir1_2 (dir_20080530_4944/dir1)
1_2.txt (dir_20080530_4944/dir1/dir1_2)
dir2 (dir_20080530_4944)
2.txt (dir_20080530_4944/dir2)

2: Recursively output all file names (full path).
dir_20080530_4944
dir_20080530_4944/top.txt
dir_20080530_4944/dir1
dir_20080530_4944/dir1/1.txt
dir_20080530_4944/dir1/dir1_1
dir_20080530_4944/dir1/dir1_1/1_1.txt
dir_20080530_4944/dir1/dir1_2
dir_20080530_4944/dir1/dir1_2/1_2.txt
dir_20080530_4944/dir2
dir_20080530_4944/dir2/2.txt

3: Scan directories in return order
dir_20080530_4944/top.txt
dir_20080530_4944/dir1/1.txt
dir_20080530_4944/dir1/dir1_1/1_1.txt
dir_20080530_4944/dir1/dir1_1
dir_20080530_4944/dir1/dir1_2/1_2.txt
dir_20080530_4944/dir1/dir1_2
dir_20080530_4944/dir1
dir_20080530_4944/dir2/2.txt
dir_20080530_4944/dir2
dir_20080530_4944

(Reference) File::Path, eval, sysopen function, F

cntl

Related Informatrion