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

Does File::find::name require the file paths returned to be added to an array if file tests are to be used?

I am asking because this code will not work as i want. The file tests always return false.

#!/usr/local/bin/perl -w # print warnings use strict; use File::Find; my $Start_dir = shift; die ">$Start_dir< is not a directory\n" if !-d $Start_dir; find( \&process, $Start_dir ); sub process { return if -f $File::Find::name; # This is success - the file exi +st return if -e $File::Find::name; print ">$File::Find::name < is not a file or was not found\n"; }

This code works as I expected

#!/usr/local/bin/perl -w use strict; use File::Find; my $Start_dir = shift; my @found =(); die ">$Start_dir< is not a directory\n" if ! -d $Start_dir; find(\&process, $Start_dir); sub process { push(@found, $File::Find::name) } foreach (@found){ if (-d $_ ) { print "This is success - the directory $_ exist\n"}; if ( -f $_) { print "This is success - the file $_ exist\n"}; }

Replies are listed 'Best First'.
Re: using file::find::name and file tests
by merlyn (Sage) on May 06, 2006 at 17:25 UTC
    $File::Find::name is a full path relative to the directory where you started the scan. During the scan, that'll be the wrong name. You want to make your tests against $_ instead, which is just the local name relative to the current place of the scan.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      the File::Find docs (and a quick warn tossed into OP's first code) say that $File::Find::name is the 'Complete pathname to the file', and not relative and all the examples given in the The wanted function section indicate the same thing..

      to OP-- you can add some debugging to print out cwd, $_, and $File::Find::name to examine exactly what's going on..
        the File::Find docs (and a quick warn tossed into OP's first code) say that $File::Find::name is the 'Complete pathname to the file', and not relative and all the examples given in the The wanted function section indicate the same thing..
        Let's recap... yes it is the complete path, but constructed from the original parameter. If you start with ".", your path will look something like "./path/to/file" which, as merlyn said, won't work as the cwd is changed to the directory the current file is in, every time.

        So, if you want an absolute path, start out with absolute paths. rel2abs from File::Spec::Functions can do wonders. You don't have to use in it the callback, just apply it to every parameter you pass to find.

        use File::Spec::Functions 'rel2abs'; find sub { blah blah } map rel2abs($_), @dirs;
        Now you'll get absolute paths.
        what is an OP?
Re: using file::find::name and file tests
by GrandFather (Saint) on May 06, 2006 at 18:07 UTC

    A simple test shows what is going on:

    use strict; use warnings; use File::Find; find (\&wanted, '..'); sub wanted { if (-e $File::Find::name) { print "Found $File::Find::name\n"; } else { print "Didn't find $File::Find::name\n"; } }

    Prints in part (Windows XP):

    Found .. Didn't find ../Ook.pl Didn't find ../test2.out.txt Didn't find ../test2.pl Didn't find ../test2.txt Didn't find ../test3.txt Didn't find ../test4.txt Didn't find ../Job Found ../Job/Func.pm Found ../Job/Game.pl Found ../Job/Game.pm Found ../Job/1st Didn't find ../Job/1st/Func.pm Didn't find ../Job/1st/Game.pl Didn't find ../Job/1st/Game.pm Didn't find ../tk Found ../tk/tkTest.pl Found ../tk/tkTest.vpd

    From which you can see that the directory passed into find is concatenated onto the front of the relative path. That is just fine if the path passed in is absolute, but can be a real pain if it it is relative because (from the find docs):

    Additionally, for each directory found, it will chdir() into that directory

    means that the path is broken when the directory is changed away from the current directory when the find was called.

    You can fix the problem by specifying no_chdir thus:

    find ({wanted => \&wanted, no_chdir => 1}, '..');

    DWIM is Perl's answer to Gödel
Re: using file::find::name and file tests
by davidrw (Prior) on May 06, 2006 at 17:28 UTC
    $File::Find::name is already the complete pathname of the file .. see "The wanted function" section in the File::Find docs.

    Your first code works for me -- i.e. it outputs nothing, which is what should happen as written. By definition, that print statement should never be reached..

    As a side note, File::Find::Rule may be of interest

    Update: See my other reply above and its followup.