Q:

fail to recursive by Perl while

I'm trying to write a function recursively searching for all the directories under a given directory. 
use strict;
use warnings;

sub printDir
{
        my $root = shift;

        opendir DIR, $root or die "can't open dir $root\n";
        my $dir;
        while ($dir = readdir DIR)
        {

                if (-d "$root/$dir" && "$dir" ne '.' && "$dir" ne '..')
                {
                        print "$dir\n";
                        &printDir ("$root/$dir");
                }
        }

}

my $root = $ARGV[0];
printDir $root;

If the directory hierarchy is like:
  A
 / \
B   C
|
D

The code stops after searching for A-B-D and C will not be searched. What's wrong with the code? 
Thanks

A:

Your directory handle is global. 
opendir DIR, $root or die "can't open dir $root\n";

It gets overwritten every time you call the sub. Once one invocation is done and returns to the last scope, DIR still points to that last directory, which was already read to the end, so it will not read anything else and stop completely as soon as the innermost directory is done reading.
You need to use lexical directory handles instead.
opendir my $dh, $root or die "can't open dir $root\n";
while (my $dir = readdir $dh)
{
    ...
}

Also see the example at readdir in perldoc.

A:

This is what File::Find is for.
use File::Find;
use feature 'say';

my $root = $ARGV[0];

find(\&wanted, $root);

sub wanted {
  say $File::Find::name if -d;
}

A:

The problem is in the following line:
opendir DIR, $root or die "can't open dir $root\n";

You are using the same symbol (i.e. DIR) for all directory handles created by all the recursive calls. You need to ensure that each call gets its own directory handle. So you change the above line to:
opendir my $dirh, $root or die "can't open dir $root\n";

Then you should also adjust the while test condition to
while ($dir = readdir $dirh)

In general, in modern perl you should always use lexical variables for file/directory handles (e.g. open my $handle,'<','somefile').

