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

First off, I apologize for the length of this post. I've tried to be brief, but I think you'll need to see both scripts to see the nature of my confusion. I've been fighting with this for most of the weekend, have tried what feels like a kazillion variations, and just can't see the forest for the trees.

Put simply, I'm having problems modularizing some code into subroutines.

I'm creating a script to process directories and files on my website. I don't want all directories processed, just certain ones. To that end, I'm using an array to exclude certain directories, as shown below:

#!/usr/bin/perl use strict; use File::Find; # -| Configuration |------- my $basepath = '/sitedir/'; my @skipdirs = ( "private", "cgi-bin", "lib", "images", "files" ); # -| Main |---------------- find (\&findHandler, $basepath ); # -| Subs |---------------- sub findHandler { # -------------------------------------------------------- # Evaluates and processes found files; # init local vars my $filename = $File::Find::name; my $dircheck = ""; my $showfile = 1; # first, should we show this file? foreach $dircheck ( @skipdirs ) { $showfile = 1; if ( $filename =~ /$dircheck+/i ) { $showfile = 0; # skip this one; last; } } if ( $showfile ) # then do so { # first, strip leading path $filename =~ s/$basepath//i; # only after directory names. if ( -d ) # add dir to hash { print "$filename\n"; } } }

When run, the above behaves as I expect, printing a list of all directories that are not being excluded by the array. (Please note that the above has been stripped down for the sake of the question.)

However, when I try to break the directory validation bit into a separate subroutine, it no longer works. Instead, it prints all of the directories, including those that were excluded in the previous version. Here's what fails to work:

#!/usr/bin/perl use strict; use File::Find; # -| Configuration |------- my $basepath = '/sitedir/'; my @skipdirs = ( "private", "cgi-bin", "lib", "images", "files" ); # -| Main |---------------- find (\&findHandler, $basepath ); # -| Subs |---------------- sub findHandler { # -------------------------------------------------------- # Evaluates and processes found files; # init local vars my $filename = $File::Find::name; my $dircheck = ""; if ( goodDir( $filename ) ) # then do so { # first, strip leading path $filename =~ s/$basepath//i; # only after directory names. if ( -d ) # add dir to hash { print "$filename\n"; } } } sub goodDir { # -------------------------------------------------------- # Evaluates a file's dir to see if we want to print it. my $filename = $_; # file we're testing my $dircheck = ""; # loop counter my $showfile = 1; # assume success # first, should we show this file? foreach $dircheck ( @skipdirs ) { $showfile = 1; if ( $filename =~ /$dircheck+/i ) { $showfile = 0; # skip this one; last; # skip rest of loop; } } return $showfile; }

My question is: What am I doing wrong with my subdirectory definition? As afar as I can tell, the logic is precisely the same, though I strongly suspect I'm missing something extraordinarily simple, a Homerism.

Please note:

Thanks in advance for any suggestions...

--f

Replies are listed 'Best First'.
Re: Problems creating sub's
by chromatic (Archbishop) on Dec 04, 2000 at 00:45 UTC
    In the second snippet, do you really mean this to be the first line of goodDir?

    my $filename = $_;   # file we're testing

    Or do you mean one of these instead:

    my $filename = shift; my ($filename) = @_; my $filename = $_[0];
Re: Problems creating sub's
by arturo (Vicar) on Dec 04, 2000 at 00:48 UTC

    I note, for those who might come across this node (and this is not meant to count as a rebuff to footpad -- I think it's good to think about why your code doesn't work, you usually (always?) learn something!) that if you want to exclude directories from being traversed by File::Find, you can set $File::Find::prune to 1 if the current directory matches the exclusion pattern.

    Below is untested ...

    # nifty trick -- make a hash to ease the lookup in the findit sub my %excludeit; # now set the keys of the hash # (== the members of your excluded directories array) # to have values of 1 @excludeit {@exclude_dirs} = (1) x @exclude_dirs; # this would be the subroutine used by File::Find sub findit { $File::Find::prune = 1 if $excludeit{$_}; # .. }

    Philosophy can be made out of anything. Or less -- Jerry A. Fodor

Re: Problems creating sub's
by footpad (Abbot) on Dec 04, 2000 at 22:07 UTC
    In lieu of an update, Chromatic nailed it. D'oh!

    In addition, arturo, no offense taken. (I'm an adult; I can take it. {grin}) You're right; I *should* have checked my inputs on the sub before posting. That would have revealed that goodDir() wasn't getting the data I thought it was.

    Interesting trick, BTW, one I'll be meditating on throughout the week.

    Mea culpa and I promise to reread Chapter 8 in "Learning Perl" and p111-121 in "Programming Perl."

    (Memo to self: Buy extra copies for home so I don't have to remember to shlep them between the office and home each night/morning.)

    Thanks for the help, folks...

    --f