http://www.perlmonks.org?node_id=967450

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

This is perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux

use strict; use warnings; use 5.010; use File::Find qw/find/; my @all; my @insub; my @outsub; my $dir = 'static'; find sub { my $f = $File::Find::name; push @all, $f; return if -d $f; push @insub, $f; }, $dir; @outsub = grep {!-d} @all; my $all_count = @all; my $insub_count = @insub; my $outsub_count = @outsub; say 'all_count = ', $all_count; say 'insub_count = ', $insub_count; say 'outsub_count = ', $outsub_count;

$dir should be set to a directory that has a little bit of depth to it.

What I expect is that $insub_count should match $outsub_count. What I get is $insub_count matching $all_count;

all_count = 436 insub_count = 436 outsub_count = 408

If you change the sense of the test in the sub to

return if ! -d $f

$insub_count becomes 0!

Similar bizarre behavior occurs with -f.

Replies are listed 'Best First'.
Re: Problem with -d inside find sub
by moritz (Cardinal) on Apr 26, 2012 at 20:27 UTC

    I think your confusion comes from ignoring this part of the File::Find documentation:

    Additionally, for each directory found, it will "chdir()" into that directory and continue the search, invoking the &wanted function on each file or subdirectory in the directory.

    So the path in $f is always relative (because static is a relative path), and the calls to chdir that File::Find performs take care that the file tests never find the file that you think should be found.

    Either pass the no_chdir => 1 option to &find, or do the file checks on $_ instead of $File::Find::name.

      Duh! Thanks.
        but remember, no_chdir slows things down considerably
      Found another interesting issue. Run the code below as is. It works fine. Then uncomment the given/when blocks and run it again. When I do that I see the same name printed out over and over instead of the correct file names.
      use strict; use warnings; use 5.010; use File::Find qw/find/; my $dir = 'dirname'; my @all; #given ($dir) { #when (-d) { my %options = ( wanted => sub { say; }, no_chdir => 1, ); find \%options, $dir; #} #} local $" = "\n"; say "@all";
        Two solutions:
        1. Declare the %options outside of the given-when blocks.
        2. say $File::Find::name;