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
.$_
isabc
.
(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.