glob() idiom

schwern on 2004-07-19T15:26:36

The folks where I'm consulting like to use */*.pl a lot. Their code is all layed out as Foo/bar.pl. This means ls */*.pl can find all their code. The handicap is they're shy of things like find and rgrep.

Anyhow, this made me think of a neat idiom to walk directories breadth-first.

my $pattern = "*.pl"; while( my @files = glob($pattern) ) { print join "\n", @files; $pattern = "*/$pattern"; }

Beats the pants off File::Find and File::Find::Rule in terms of performance.


Caveat

Dom2 on 2004-07-19T15:46:02

It may well work faster, unless glob() is still implemented by call /bin/csh on your box.

Of course, I don't know of a platform that still does things that way, but I'm sure that somebody does...

-Dom

minor nits

jmm on 2004-07-19T16:18:11

It'll quit too soon if someone created foo/bar/baz/and/another/thing/plugh.pl, yet there is any level between 1 and 5 that contains no .pl files in any directory at that level. It'll give a wrong answer if someone created a directory (or pipe or ...) that matches *.pl - you'll have someone to blame for your problem, though.

This should work (modulo any bugs - I just typed it in off the top of my head...):

@dirs = ( '.' );

while (@dirs) {
    my $dir = shift @dirs;
    DIR = opendir $dir;
    foreach my $file (<DIR>) {
        my $fullfile = "$dir/$file";
        -f $fullfile && ($file =~ /\.pl$/) && print "$fullfile\n";
        -d _ && push @dirs, $fullfile;
    }
}

Re:minor nits

avik on 2004-09-03T00:56:05

but his code works on other (non *nix) platforms...