sid_com
sid_com

Reputation: 25117

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 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";

Upvotes: 2

Views: 938

Answers (3)

dave4420
dave4420

Reputation: 47052

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.

Upvotes: 1

Sinan Ünür
Sinan Ünür

Reputation: 118128

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";

Upvotes: 2

Powertieke
Powertieke

Reputation: 2408

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...

Upvotes: 0

Related Questions