bob_saginowski bob_saginowski - 7 months ago 15
Perl Question

Print files and subdirectories of given directory

I am trying to get all files and directories from a given directory but I can't specify what is the type (file/ directory). Nothing is being printed. What I am doing wrong and how to solve it. Here is the code:

sub DoSearch {
my $currNode = shift;
my $currentDir = opendir (my $dirHandler, $currNode->rootDirectory) or die $!;

while (my $node = readdir($dirHandler)) {
if ($node eq '.' or $node eq '..') {
next;
}

print "File: " . $node . "\n" if -f $node;
print "Directory " . $node . "\n" if -d $node;
}

closedir($dirHandler);
}

Answer

readdir returns only the node name without any path information. The file test operators will look in the current working directory if no path is specified, and because the current directory isn't $currNode->rootDirectory they won't be found

I suggest you use rel2abs from the File::Spec::Functions core module to combine the node name with the path. You can use string concatenation, but the library function takes care of corner cases like whether the directory ends with a slash

It's also worth pointing out that Perl identifiers are most often in snake_case, and people familiar with the language would thank you for not using capital letters. They should especially be avoided for the first character of an identifier, as names like that are reserved for globals like package names

I think your subroutine should look like this

use File::Spec::Functions 'rel2abs';

sub do_search {
    my ($curr_node) = @_;
    my $dir         = $curr_node->rootDirectory;

    opendir my $dh, $dir or die qq{Unable to open directory "$dir": $!};

    while ( my $node = readdir $dh ) {
        next if $node eq '.' or $node eq '..';

        my $fullname = rel2abs($node, $dir);

        print "File:     $node\n" if -f $fullname;
        print "Directory $node\n" if -d $fullname;
   }
}

An alternative method is to set the current working directory to the directory being read. That way there is no need to manipulate file paths, but you would need to save and restore the original working directory before and after changing it

The Cwd core module provides getcwd and your code would look like this

use Cwd 'getcwd';

sub do_search {
    my ($curr_node) = @_;

    my $cwd = getcwd;
    chdir $curr_node->rootDirectory or die $!;

    opendir my $dh, '.' or die $!;

    while ( my $node = readdir $dh ) {
        next if $node eq '.' or $node eq '..';

        print "File: \n" if -f $node;
        print "Directory $node\n" if -d $node;
   }

   chdir $cwd or die $!;
}