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

Dear all,

I do some filetests on different directories. As expected, just using -filetest $file is not working. However, if I use Cwd's abs_path($file) I get the full path but the filetest fails. In contrast, concatenating the path and $file works, with and without abs_path(). Now I'm wondering if this is by purpose, a "bug" in filetest/Cwd or if I just miss something.

Cheers, LeJosh

I attached a minimal working example.

Perl version: perl 5, version 14, subversion 2 (v5.14.2) built for x86_64-linux-gnu-thread-multi

Cwd version: 3.36

Running on: Linux: Linux dh2-biotek16 3.2.0-55-generic #85-Ubuntu SMP Wed Oct 2 12:29:27 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

use strict; use warnings; use Cwd 'abs_path'; my($path) = @ARGV; ## add path to a directory print "Input path: $path\n"; print "## no modifications to readdir output (as mentioned in the docs + this is bad for filetesting)\n"; opendir(my $dh, $path) or die "Cannot open dir $path: $!\n"; while(readdir($dh)) { #print "Testing $_\n"; if(-z $_) { print "File $_ is empty\n\n"; } elsif(-d $_) { print "File $_ is a directory\n\n"; } elsif(-f $_) { print "File $_ is a plain file\n\n"; } elsif(-B $_) { print "Path $_ points\tto a binary file\n\n"; } else { print "Not recognized: $_\n\n"; } } closedir($dh); print "## using abs_path\n"; opendir(my $dh1, $path) or die "Cannot open dir $path: $!\n"; while(readdir($dh1)) { my $abs_path = abs_path($_); #print "Testing $abs_path\n"; if(-z $abs_path) { print "Path $abs_path\tpoints to an empty file\n\n"; } elsif(-d $abs_path) { print "Path $abs_path\tis a directory\n\n"; } elsif(-f $abs_path) { print "Path $abs_path points\tto a plain file\n\n"; } elsif(-B $abs_path) { print "Path $abs_path points\tto a binary file\n\n"; } else { print "Not recognized: $abs_path\n\n"; } } closedir($dh1); print "## using $path/filename\n"; opendir(my $dh2, $path) or die "Cannot open dir $path: $!\n"; while(readdir($dh2)) { my $abs_path_mod = abs_path("$path/$_"); #print "Testing $abs_path_mod\n"; if(-z $abs_path_mod) { print "Path $abs_path_mod\tpoints to an empty file\n\n"; } elsif(-d $abs_path_mod) { print "Path $abs_path_mod\tis a directory\n\n"; } elsif(-f $abs_path_mod) { print "Path $abs_path_mod points\tto a plain file\n\n"; } elsif(-B $abs_path_mod) { print "Path $abs_path_mod points\tto a binary file\n"; } else { print "Not recognized: $abs_path_mod\n"; } } closedir($dh2); print "## using $path/filename w/o abs_path\n"; opendir(my $dh3, $path) or die "Cannot open dir $path: $!\n"; while(readdir($dh3)) { my $path_mod = "$path/$_"; #print "Testing $path_mod\n"; if(-z $path_mod) { print "Path $path_mod\tpoints to an empty file\n\n"; } elsif(-d $path_mod) { print "Path $path_mod\tis a directory\n\n"; } elsif(-f $path_mod) { print "Path $path_mod points\tto a plain file\n\n"; } elsif(-B $path_mod) { print "Path $path_mod points\tto a binary file\n"; } else { print "Not recognized: $path_mod\n"; } } closedir($dh3);

Replies are listed 'Best First'.
Re: Cwd's abs_path not working with filetests?
by Corion (Patriarch) on Nov 26, 2013 at 09:56 UTC

    abs_path will still only work relative to the current working directory. Which means that the results for relative paths will also be relative to your current working directory and not $path.

      Thx for the fast reply. If I got this right, it means to filetest a random path/file it's necessary to:

      1. extract the path and chdir into the specified directory

      2. perform the filetest

      3. chdir back to the cwd

      I do not want to lean too far out of the window, but isn't this kinda defeating a purpose of abs_path()?

      Cheers, LeJosh

        but isn't this kinda defeating a purpose of abs_path()?

        I think you've misunderstood the purpose of abs_path(). It resolves any symlinks along the given path and returns the canonicalized "absolute" path with all symlinks removed (see also "man realpath").

        If you give it a relative path, it assumes it's relative to the CWD (as usual), not to whatever readdir() is currently processing...

        I do not want to lean too far out of the window, but isn't this kinda defeating a purpose of abs_path()?

        Do you know what readdir does? The mistake you're making is explained in readdir documentation, so read perldoc readdir or simply use Path::Tiny and be done with it

Re: Cwd's abs_path not working with filetests? (dont use readdir because of cwd
by Anonymous Monk on Nov 26, 2013 at 10:21 UTC

    dont use readdir because of cwd

    readdir isn't for people its for computers, don't use readdir, use Path::Tiny

    Let Path::Tiny be your interface to Cwd and readdir

    #!/usr/bin/perl -- use strict; use warnings; use Path::Tiny qw/ path /; Main( @ARGV ); exit( 0 ); sub Main { my( $dir ) = @_; my $readdir = path( $dir )->realpath ->iterator( { qw/ recurse 0 / }); while( my $file = $readdir->() ){ Staterator( $file ); } } sub Staterator { local( $_ ) = @_; if( -z ){ ... } }
      Thanks for pointing to Path::Tiny. Was not aware of that.