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

Greetings, monks.

I'm using File::Find in my current mini-project, and it's working well, but I'm having problems getting the full pathnames of the files it finds.

To start, my script takes from the command line a directory to pass to File::Find. This direcory can be a relative path.

I know that I can use the follow attribute to File::Find to get at the $fullname variable, but there may or may not be a symlink somewhere in the search path, which might muck up the results.

So, I tried using File::Spec and abs2rel, but am getting odd results if I pass a relative path. It'd be best to show my code and some output, so here's the relevant bits:

!/usr/bin/perl -w use strict; use Image::Size; use Data::Dumper; use File::Find; use File::Spec; use vars qw/*name *dir/; *name = *File::Find::name; *dir = *File::Find::dir; die "Usage: filecomp <path> <pattern>\n" unless (@ARGV == 2); my ($path, $pat) = @ARGV; my $qpat = qr/$pat/i; chomp (my $cwd = `pwd`); my $abspath = File::Spec->rel2abs($path, $cwd); print "Absolute base path is ",$abspath, "\n"; print "Location Filesize\n"; File::Find::find({wanted => \&wanted, # follow => 1 }, $path); sub wanted { /^$qpat/ && do { my $fullname = File::Spec->rel2abs($name, $abspath); printf "\n ------------- \n\$fullname is %s\n", $fullname; printf "\$name is %s\n", $name; --Results, with output from find to show that the files do exist-- [eggie@sunlink eggie]$ find tmp -name 'term*' -ls 4103 1 -rw------- 1 eggie eggie 160 Sep 2 16:52 tmp +/terminal.txt 675863 1 -rw------- 1 eggie eggie 160 Sep 3 14:35 tmp +/foo/terminal.txt [eggie@sunlink eggie]$ filecomp.pl tmp 'term.*' Absolute base path is /home/eggie/tmp Location Filesize ------------- $fullname is /home/eggie/tmp/tmp/terminal.txt $name is tmp/terminal.txt ------------- $fullname is /home/eggie/tmp/tmp/foo/terminal.txt $name is tmp/foo/terminal.txt
See the extra "tmp/" in the $fullname variable? Things look even uglier the deeper in the subdir that a file is found, something like /home/eggie/tmp/foo/bar/baz/foo/bar/baz/terminal.txt when it should be only /home/eggie/foo/bar/baz/terminal.txt Is this a bug/limitation in File::Spec? Do any of you know of a way around this, other than enabling follow in File::Find? (This is Perl, fer crying out loud, it should be possible.) Thanks in advance.

--

There are 10 kinds of people -- those that understand binary, and those that don't.

Replies are listed 'Best First'.
Re: File::Find, File::Spec, and full paths.
by sauoq (Abbot) on Sep 03, 2002 at 19:45 UTC

    You are setting your $abspath variable incorrectly. $File::Find::name will be the relative path from the directory you are in (i.e. `pwd`) not the directory where you start looking (i.e. the first argument to your script.) Try just setting $abspath to `pwd` and chomp.

    Alternatively, you could call find() with $abspath rather than $path.

    -sauoq
    "My two cents aren't worth a dime.";
    
      Or rather than `pwd`, use Cwd; and then set $abspath to cwd(). That will, the documentation says, most likely do `pwd` on Unix systems. However, Cwd will work on Windows and other systems where pwd isn't available.

      Makeshifts last the longest.

      This seemed to do the trick. I didn't really want to use find() with an absolute path if the user specified a relative path, as I wanted the value of $name to be relative if relative was supplied on the command line. I had a strong feeling that the problem was in how I was calling rel2abs, but couldn't figure out exactly how. Thanks to all that replied.

      --

      There are 10 kinds of people -- those that understand binary, and those that don't.

Re: File::Find, File::Spec, and full paths.
by metlhed_ (Beadle) on Sep 03, 2002 at 19:17 UTC

    I believe what your looking for is $File::Find::name. This will give you the complete pathname to the file. For more information check out File::Find on CPAN.

      He already is using $File::Find::name. He said he wants an absolute path not just a "complete pathname." $File::Find::name is a relative path appended to the path argument supplied to the find function. So, if you provide a relative path argument, $File::Find::name will also be relative.

      -sauoq
      "My two cents aren't worth a dime.";