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

Well I am still having trouble with syntax in Perl. I have tried writting this in several different ways but with no luck. I know that I could be using File::File or other methods but I learn nothing by stealing code. I have tried the C++ method, foreach and while loops.

The problem is that this code will work every now and again but most of the time it will loop on forever at the first end to a chain. I think a variable is not being cleared or something.

The code is as follows...

my $dir = "C:/" sub recurseDir2 { my @temp = (glob @_[0]); foreach (@temp) { if (-d $_) { print "Directory: $_" , "\n" ; recurseDir("$_/*"); }else{ if (-f $_) { print "File: $_ \n"; } } } } recurseDir2($dir)
So whats the problem with this one.

Thanks
Paul Neale

Replies are listed 'Best First'.
Re: Recursive sub
by dragonchild (Archbishop) on Sep 23, 2003 at 17:58 UTC
    First - if you're doing this for a learning exercise, that's fine. But, using File::Find is NOT "stealing code". It is using well-tested and well-written solutions to common problems. I hope you wouldn't think you'd have to rewrite CGI, DBI, or XML::Parser because you'd be "stealing code".

    That said, you have a few "issues" with your code. Try the following:

    use File::Spec; my $dir = "C:\"; sub recurseDir2 { foreach (glob shift) { if (-d) { print "Directory: '$_'\n" ; recurseDir2(File::Spec->catfile($_, '*')); next; } if (-f) { print "File: '$_'\n"; } } } recurseDir2($dir)

    I wasn't able to reproduce your problem, but I think I know where it might have come from. You're on a Windows system, but using the Unix directory syntax. This is why modules exist, to make sure you don't get screwed up. File::Spec will make sure you use the right directory separator for your system. This isn't "stealing code" - this is intelligent re-use of well-thought out solutions.

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

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

      Thanks dragonchild, I am aware that I am not stealing code. I was just making the point that I don't want to just cut and paste code that I don't understand. For me to learn Perl I need to be able to write my own code so that I get a full understanding.

      I hadn't seen the File::Spec module, I will read up on it.

      In your code you are short forming

       foreach (glob shift)

      I assume by not supplying the array. Is this the case?

      This is one area that I am having difficutly in reading other peoples code at this point, Perl makes allot of assumptions that I am not aware of yet, or just don't remember at this point.

      Paul Neale

        There are not many that I can help because of my relative new-ness to perl! But you seem willing to put forth the effort, and I can answer some of your questions. Well, I would like to suggest you pick up a copy of Learning Perl 3rd Ed Written by our very own Merlyn. Trust me, you will learn a lot from it.

        In the line foreach (glob shift) Perl is using @_ as it's default.

        LR

        Whip me, Beat me, Make me use Y-ModemG.
Re: Recursive sub
by BrowserUk (Patriarch) on Sep 23, 2003 at 18:26 UTC

    The first problem is that the code you posted doesn't compile:

    P:\test>perl -c -mstrict -w junk.pl Scalar value @_[0] better written as $_[0] at junk.pl line 6. syntax error at junk.pl line 5, near "sub recurseDir2 " Can't use global @_ in "my" at junk.pl line 6, near "glob @_" syntax error at junk.pl line 17, near "}" junk.pl had compilation errors.

    If you correct the missing semicolon on the first line, the use of @_[0] instead of $_[0] in the third and the ommission of the '2' in the subname in the 7th line, it appears to work fine.

    Adding -w and use strict isn't obligatory, but it would probably have saved your need to post this question.

    #! perl -w use strict; my $dir = "C:/"; sub recurseDir2 { my @temp = (glob $_[0]); foreach (@temp) { if (-d $_) { print "Directory: $_" , "\n" ; recurseDir2("$_/*"); }else{ if (-f $_) { print "File: $_ \n"; } } } } recurseDir2($dir)

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.

      All good stuff. The missing ellements were typos as I posted from another machine and couldn't cut and paste.

      I have not seen this before  #! perl -w where can I find information on this. It is commented out as well so how can it do anything?

      Paul Neale

        It's often called the shebang line, and is mostly used on unix systems to tell the shell where it should look for the perl binary. Windows doesn't use this mechanism to find the binary, so that use is mute.

        However, if the line is present, perl will inspect it and respect (some of) the runtime switches (see Perlrun).

        I use it as a "reminder" for switches that I have permenantly enabled through the assoc/ftype mechanism (-sw) --mostly so people can see what I use when I post code.

        I also use it to enabled individual switches on a case by case basis. The most frequent one being -l as it save me having to add "\n" to the end of every print line. Of course, there are times when you don't want a newline printed, in which case I just use printf $string; instead. Works for me:)


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
        If I understand your problem, I can solve it! Of course, the same can be said for you.

      I just tried use strict and it stops everything from printing. Should this happen?

      Paul Neale

        No. use strict; shouldn't stop everything from printing...and it doesn't on my system.

        I suspect that you are running your script from the Explorer by double clicking and the reason you see no output is because you have a compilation error that prevents your script reaching the sleep statement and so the window is disappearing before you have a chance to read the error messages produced.

        I would advise you to start using the command line, at least for testing your scripts.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
        If I understand your problem, I can solve it! Of course, the same can be said for you.

Re: Recursive sub
by Not_a_Number (Prior) on Sep 23, 2003 at 19:30 UTC

    A couple of remarks on top of those of BrowserUK:

    1) Perl has an elsif option, so you can simplify you sub thusly:

    sub recurseDir2 { my @temp = (glob $_[0]); foreach (@temp) { if (-d $_) { print "Directory: $_" , "\n" ; recurseDir2("$_/*"); } elsif (-f $_) { print "File: $_ \n"; } } }

    2) There might (I'm not sure with Windoze) be some 'things' in your directories meet neither the -f nor the -d test. In which case, I would recommend adding an else clause:

    sub recurseDir2 { my @temp = (glob $_[0]); foreach (@temp) { if (-d $_) { print "Directory: $_" , "\n" ; recurseDir2("$_/*"); } elsif (-f $_) { print "File: $_ \n"; } else { next; } } }

    hth

    dave

      Your else clause is unnecessary, as it's not doing anything. There definitely will be stuff (in many directories) that don't meet the -f or -d tests. In that case, he will just fall through and the loop will continue with the next item.

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

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

        You're right, of course. I originally had something like this:

        my @anomalies; sub recurseDir2 { my @temp = (glob $_[0]); foreach (@temp) { if (-d $_) { print "Directory: $_" , "\n" ; recurseDir2("$_/*"); } elsif (-f $_) { print "File: $_ \n"; } else { push @anomalies, $_; } } } print "Anomalies: @anomalies";

        but as I found no 'anomalies' in my filepaths I stupidly changed my code to what I posted. Thanks for pointing out my mistake.

        dave

      Interestingly glob didnt work on my installation of ActivePerl.

      readdir() works a treat tho.. funny how the -d and -f does not always work and I see most files and folders listed in the else

      sub recurseDir2 { opendir(DIR, $_[0]); my @temp = readdir(DIR); closedir DIR; #my @temp = (glob $_[0]); foreach (@temp) { if (-d $_) { print "Directory: $_" , "\n" ; recurseDir2("$_/*"); } elsif (-f $_) { print "File: $_ \n"; }else{ print "Other: $_ \n"; } } } recurseDir2('c:/'); ---8<--- Other: deleteme.htm Other: I386 Other: DISCOVER Other: AUTOEXEC.BAT Other: CONFIG.SYS Other: deleteme.gif Other: BOOTLOG.TXT Other: WINDOWS Other: casa_gms.zip Other: Answer.txt Other: Recycled Other: sacoss_crm.zip Other: convert_rarossa.zip Other: mpcsetup.log File: console.zip Directory: data ---8<---
      because windows folders usually don't have extensions and files usually do have extensions this concept could be used in a controlled environment to recurse through all folders (things with no extension)
      ___ /\__\ "What is the world coming to?" \/__/ www.wolispace.com