jeddak has asked for the wisdom of the Perl Monks concerning the following question:

A Perl novice on my third and most serious attempt in ten years at learning the language.

As an exercise, I've cobbled together the following script from example snippets. It's supposed to recursively list directories starting at either the current directory or the directory specified by a command-line argument (-d).

I'd love to know why the thing seems unwilling to go deeper than about three levels. Now, before anyone criticizes how this was written: I know this is probably a very un-Perl-like program. I know that File::Find is a better tool. But it seems as though my approach should work.

If anyone could help shed light as to why this program isn't behaving as expected, I'd be very grateful.

-------------------
#!/usr/bin/perl -w use Cwd; use Getopt::Std; use vars qw($opt_d); getopt('d'); local $start_dir = ($opt_d) ? $opt_d : getcwd; print "\n"; listDir($start_dir); print ("\n\nfinished.\n\n"); sub listDir { local $thisdir = $_[0]; print "\n$thisdir:\n"; opendir THISDIR, $thisdir; #get all entries, filter in directories # then filter out .. and . local @allentries = readdir THISDIR; local @directories = sort grep !/^\.\.?$/, (grep -d, @allentries); local $entry = ""; closedir THISDIR; foreach $entry(@allentries) { print "\t$entry\n"; } foreach $entry (@directories) { chomp($entry); &listDir($thisdir . '/' . $entry ); } }
-------------

Additional info:

I'm running this in a Cygwin sh on WinNT (blech, chhhhhk ptooey). Haven't tried it yet on a "real" *nix environment, yet. Perl v5.6.1.

Replies are listed 'Best First'.
(tye)Re: Recursive Directory Listing
by tye (Sage) on Oct 12, 2001 at 20:42 UTC

    Standard mistake. (: -d needs to be -d "$thisdir/$_" since you didn't chdir into $thisdir.

            - tye (but my friends call me "Tye")
Re: Recursive Directory Listing
by tstock (Curate) on Oct 12, 2001 at 21:00 UTC
    Tye beat me to the answer, so i'll just comment on the code.

    remeber
    use strict; use warnings; $thisdir.'/'.$entrey could be written "$thisdir/$entry"

    and you can always
    use constant DEBUG => 1 and then
    print "what is $this\n" if DEBUG;
    to see the value of your variables

    Tiago

      Tiago, Tstock:

      Thanks and thanks.

      Apologies for posting a probably annoyingly FAQ. I obviously didn't check the site FAQ; if I had, I would have worded this question differently.

Re: Recursive Directory Listing
by Hofmator (Curate) on Oct 15, 2001 at 17:49 UTC

    OK, some additional remarks after your problem is solved - as always, there's room for improvement:

    • use strict and warnings - this was already suggested but it's important so I repeat it :)
    • Substitute all the uses of local and use my instead. For further reading I strongly recommend Coping with Scoping by Dominus. I suspect the snippets you used to put this together were old and came from the time before my ...
    • Use getopts instead of getopt and use the hash variant of the function call. These recommendations are not really necessary in this simple program but are in general a good idea (for the differences read up in the Getopt::Std documentation).
    • Don't do nested greps, you can chain the tests together with &&

    Here is my adapted version to show how these things look like:

    #!/usr/bin/perl use strict; use warnings; use Cwd; use Getopt::Std; my %opts; getopts('d:', \%opts); my $start_dir = $opts{d}; $start_dir = getcwd() unless defined ($start_dir); listDir($start_dir); print ("\n\nfinished.\n\n"); sub listDir { my $thisdir = $_[0]; print "\n$thisdir:\n"; opendir THISDIR, $thisdir; my @allentries = readdir THISDIR; my @directories = sort grep(-d "$thisdir/$_" && !/^\.\.?$/, @allen +tries); closedir THISDIR; foreach my $entry (@allentries) { print "\t$entry\n"; } foreach my $entry (@directories) { chomp($entry); listDir("$thisdir/$entry"); } }

    -- Hofmator

      this works... that's all you can say about it...