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

Okay, I think this should not be too tough, but I am really messing it up. I have a directory with multiple subdirectories and files therin. Inside each of those subdirectories, I have even more files and subdirectories, ad nauseam. Each time is see a file, I want to sent it to a new subroutine.

The problem is I am not able to navigate through the different subdirectories at all, so I only pull out the top level of files. I am basically opening the parent, reading everything into an array, and testing to see if it is a directory or a file.

If it is a directory, I want to open that file up and look inside. I thought that I could call the same subroutine from itself to continue the navigate down, but I can't seem to get that part working. This is what I am doing so far:

sub readindirs { my ($dirname) = @_; opendir(NEWDIR, $dirname) or die $!"; @newfiles = grep { $_ ne '.' and $_ ne '..' } readdir NEWDIR; closedir NEWDIR; $length = scalar(@newfiles); for ($i = 0; $i < $length; $i++) { if (opendir(DIR1, $newfiles[$i])) { #this is where i want to re-call the sub &readindirs($newfiles[$i]); } else { &parse_sub_routine } } }
I thought I could do this and think that the problem may be in the reassign of the directory handle, but after trying a few workarounds, I am a little stumped. Any advice/jeering would be appreciated. Thanks a lot.

Replies are listed 'Best First'.
Re: Navigating Dierctories Recursively
by sauoq (Abbot) on Oct 16, 2003 at 20:27 UTC
    Any advice/jeering would be appreciated.
    use File::Find;
    -sauoq
    "My two cents aren't worth a dime.";
    
Re: Navigating Dierctories Recursively
by dragonchild (Archbishop) on Oct 16, 2003 at 20:30 UTC
    Would Find::File help here?

    Also, using the OO interfaces IO::Dir and IO::File may be helpful.

    And, taking your code as it is and fixing it ...

    sub readindirs { my ($dirname) = @_; opendir(NEWDIR, $dirname) or die $!"; my @newfiles = grep { $_ ne '.' and $_ ne '..' } readdir NEWDIR; closedir NEWDIR; foreach my $name (@newfiles) { if (-d $name) { readindirs($name); } else { parse_sub_routine($name); } } }

    The problem you were having was that you were clobbering @newfiles because you weren't scoping it to each invocation of the subroutine. Next time, add use strict; to the top of your script and it will help.

    ------
    We are the carpenters and bricklayers of the Information Age.

    The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

    ... strings and arrays will suffice. As they are easily available as native data types in any sane language, ... - blokhead, speaking on evolutionary algorithms

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      Hmmm... I tried fixing the code as you suggested, and ended up with the same problem. I goes into one directory and no further than that level. I am trying to avoid using the modules, because I am on the road and need to email this to someone who does not really know perl. I am getting the problem where it reads in the directory the first time, and every other time treats the directory like a file (as if the if (-d $name) piece was failing).

      I am running the following:

      #!/usr/bin/perl; use strict; sub readindirs { my ($dirname) = @_; print "$dirname -> dirname \n"; opendir(NEWDIR, $dirname) or die $!; my @newfiles = grep { $_ ne '.' and $_ ne '..' } readdir NEWDIR; closedir NEWDIR; foreach my $name (@newfiles) { if (-d $name) { print "name:: $name \n"; readindirs($name); } else { print "parse file : $name \n"; #&parse_file($name); } } } &readindirs('.');

      Which results in this:

      . -> dirname name:: about about -> dirname parse file : aic3.pl parse file : contact parse file : coredocs parse file : footer.inc parse file : index.html parse file : nav.js parse file : organization parse file : overview parse file : programs parse file : rightnav.inc parse file : template.html parse file : top.inc parse file : about2.zip parse file : aic.pl parse file : aictemp.pl
      Of which contact, coredocs, organization, overview, and programs are directories.

      I am doing this on a windows distr. and am not really a windows person, I know that there are a few differences between *nix and windows perl, is this one of them? The other thing, which is purely for my own interest, is how is  if (-d $name) better/worse than (opendir(DIR, $name)).

      Thanks a lot for your help. If I can't figure it out soon, I think that I will go to the modules.

        *smacks head repeatly against keyboard* This is why I use modules whenever possible.
        my @newfiles = map { File::Spec->catfile($dirname, $_) } grep { $_ ne '.' and $_ ne '..' } readdir NEWDIR;

        You gotta prepend the directory name onto what you read from the DIR handle.

        ------
        We are the carpenters and bricklayers of the Information Age.

        The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

        ... strings and arrays will suffice. As they are easily available as native data types in any sane language, ... - blokhead, speaking on evolutionary algorithms

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Navigating Dierctories Recursively
by vek (Prior) on Oct 16, 2003 at 21:39 UTC
Re: Navigating Dierctories Recursively
by data64 (Chaplain) on Oct 17, 2003 at 01:28 UTC