Home > database >  Perl abs_path undefined return using File::Find::dir value from relative directory
Perl abs_path undefined return using File::Find::dir value from relative directory

Time:01-20

A Perl script running on macOS takes a directory argument and then calls the File::Find &wanted() function to process the contents.

If I supply the directory as an absolute path (e.g. "/Users/sw/Downloads/FGT") I have no problems.

But if I supply a relative path (i.e. "." when run from above directory) I get an error.

The error happens when processing a file in a subdirectory: it is always the first file in the particular subdirectory (the first second level subdirectory) that generates the error (if I create or touch a new file with an alphabetically earlier name than any existing one in the directory, it is this new file that causes the error). Many earlier files are processed OK.

Complete simplified code below, with output.

So why does the below "abs_path" call give an undefined result for this one particular file (first file in first second level subdirectory)?

COMPLETE CODE:

#!/usr/local/bin/perl
use warnings;
use English;
use vars qw ( $VERSION );
use Cwd 'abs_path';
use File::Find;
find({ wanted => \&processFile, follow => 0 }, $ARGV[0]); #we do NOT follow symbolic links
exit();
sub processFile
{
    if (substr($_,0,1) eq ".") { return; } #ignore entry starting with dot 
    print "\nPROCESSING WITH:\n";
    print ">> \$File::Find::dir = <<$File::Find::dir>>\n";
    print ">> \$_ = <<$_>>\n";
    print ">> \$File::Find::name=<<$File::Find::name>>\n";
    my $dirAbsPath=abs_path($File::Find::dir);
    die "ERROR: undef abs_path() using Find::File::dir value!\n" if ! defined $dirAbsPath;
    print "Dir Abs Path is <<$dirAbsPath>>\n";
}

OUTPUT:

PROCESSING WITH:
>> $File::Find::dir = <<.>>
>> $_ = <<L1DIR>>
>> $File::Find::name=<<./L1DIR>>
Dir Abs Path is <</Users/sw/Downloads/FGT>>

PROCESSING WITH:
>> $File::Find::dir = <<./L1DIR>>
>> $_ = <<LPT1.csv>>
>> $File::Find::name=<<./L1DIR/LPT1.csv>>
Dir Abs Path is <</Users/sw/Downloads/FGT/L1DIR/L1DIR>>

PROCESSING WITH:
>> $File::Find::dir = <<./L1DIR>>
>> $_ = <<L2DIR2>>
>> $File::Find::name=<<./L1DIR/L2DIR2>>
Dir Abs Path is <</Users/sw/Downloads/FGT/L1DIR/L1DIR>>

PROCESSING WITH:
>> $File::Find::dir = <<./L1DIR/L2DIR2>>
>> $_ = <<abc>>
>> $File::Find::name=<<./L1DIR/L2DIR2/abc>>
ERROR: undef abs_path() using Find::File::dir value!

DIRECTORY TREE OF ".":

sw@Max FGT % tree .
.
└── L1DIR
    ├── L2DIR1
    │   └── LD.csv
    ├── L2DIR2
    │   ├── abc
    │   └── x.csv
    ├── L2DIR3
    │   └── xsym2 -> T2/x.csv
    └── LPT1.csv

CodePudding user response:

$File::Find::dir is relative to the original CWD. But File::Find changes the CWD unless you use no_chdir => 1.


When processing ./L1DIR/L2DIR2/abc with no_chdir => 0 (default),

  • The CWD is $orig_cwd/./L1DIR/L2DIR2.
  • $File::Find::name is ./L1DIR/L2DIR2/abc.
  • $File::Find::dir is ./L1DIR/L2DIR2.
  • $_ is abc.

(Where $orig_cwd is the absolute path of . before you call find.)

So that means that abs_path( $File::Find::dir ) is the absolute path of $orig_cwd/./L1DIR/L2DIR2/./L1DIR/L2DIR2, which obviously fails.

Using abs_path(".") would work.


When processing ./L1DIR/L2DIR2/abc with no_chdir => 1,

  • The CWD is $orig_cwd.
  • $File::Find::name is ./L1DIR/L2DIR2/abc.
  • $File::Find::dir is ./L1DIR/L2DIR2.
  • $_ is ./L1DIR/L2DIR2/abc.

So that means that abs_path( $File::Find::dir ) is the absolute path of $orig_cwd/./L1DIR/L2DIR2, which is what you want.

I prefer to avoid all those needless chdir, I prefer using no_chdir => 1 at all times.

  •  Tags:  
  • perl
  • Related