What's that best way to move through directories?
Are both of the examples below OK, or is the second one bad style?
Case 1: Stay in 开发者_JAVA百科top directory and use catdir to access subdirectories
#!/usr/bin/env perl
use warnings; use strict;
my $dir = 'my_dir_with_subdir';
my ( $count, $dh );
use File::Spec::Functions;
$count = 0;
opendir $dh, $dir or die $!;
while ( defined( my $file = readdir $dh ) ) {
next if $file =~ /^\.{1,2}$/;
my $sub_dir = catdir $dir, $file;
if ( -d $sub_dir ) {
opendir my $dh, $sub_dir or die $!;
while ( defined( my $file = readdir $dh ) ) {
next if $file =~ /^\.{1,2}$/;
$count++;
}
closedir $dh or die $!;
}
else {
$count++;
}
}
closedir $dh or die $!;
print "$count\n";
Case 2: Change to subdirectories and restore top directory before exit
use Cwd;
my $old = cwd;
$count = 0;
opendir $dh, $dir or die $!;
chdir $dir or die $!;
while ( defined( my $file = readdir $dh ) ) {
next if $file =~ /^\.{1,2}$/;
if ( -d $file ) {
opendir my $dh, $file or die $!;
chdir $file or die $!;
while ( defined( my $file = readdir $dh ) ) {
next if $file =~ /^\.{1,2}$/;
$count++;
}
closedir $dh or die $!;
chdir $dir;
}
else {
$count++;
}
}
closedir $dh or die $!;
chdir $old or die $!;
print "$count\n";
Your question is whether you should change to the directories you are going through or stay in the top level directory.
The answer is: It depends.
For example, consider File::Find. The default behavior is to indeed change directories. However, the module also provides a no_chdir
option in case that is not desirable.
In the case of your examples, File::Find
is probably not appropriate because you do not want to recurse through all subdirectories but only one. Here is a File::Slurp::read_dir based variation on your script.
#!/usr/bin/perl
use strict; use warnings;
use File::Slurp;
use File::Spec::Functions qw( catfile );
my ($dir) = @ARGV;
my $contents = read_dir $dir;
my $count = 0;
for my $entry ( @$contents ) {
my $path = catfile $dir, $entry;
-f $path and ++ $count and next;
-d _ and $count += () = read_dir $path;
}
print "$count\n";
For your example, it's best to change to subdirectories, and don't bother changing back to the original directory at the end. That's because each process has its own "current directory", so the fact that your perl script is changing it's own current directory does not mean that the shell's current directory is changed; that stays unaltered.
If this was part of a larger script it would be different; my general preference then would be not to change directory, just to reduce confusion over what the current directory is at any point in the script.
Use File::Find, as you already proposed :)
It's almost always better to use a module for solved problems like this than to roll your own, unless you really want to learn about walking dirs...
精彩评论