Search code examples
perlif-statementfile-writing

Writing to a file inside if statement not working in Perl


I've looked around here a bit and found similar questions but not exactly. If there is one, I apologize and please point me to it.

I have the following code. I'm trying to create a csv file of simply an ID pulled from a filename and the filename itself. This is the ENTIRE script.

use strict;
use warnings;
use File::Find;

find( \&findAllFiles, '.');
exit;

sub findAllFiles {

my @fp1;
my @fp2;
my $patId;
my $filename;
my $testvar = "hello again";


$filename = $File::Find::name;

if ($filename =~ /\.pdf$/) {
open (my $fh, '>', 'filenames.csv') or die "Failed to open - $!\n";
print $fh "starting...$testvar\n" or die "Failed to print to file - $!\n";
    @fp1 = split('/', $filename);
    @fp2 = split('_', $fp1[-1]);
    $patId = $fp2[-1];
    $patId =~ s/\.pdf$//;
    print "Adding $patId, file = $filename\n";
    print $fh "$patId,$filename\n" or die "File print error: $!";
close $fh or warn "close failed! - $!";
}


return;
}

The line that prints to the screen, prints perfectly. If I take the file open/close and the first print statement out of the if block, it prints that line into the file, but not the data inside the block. I've tried every combo I can think of and it doesn't work. I've alternated between '>' and '>>' since it clearly needs the append since it's looping over filenames, but neither works inside the if block.

Even this code above doesn't throw the die errors! It just ignores those lines! I'm figuring there's something obvious I'm missing.


Solution

  • Quoting File::Find::find's documentation:

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

    It means that when you open inside findAllFiles, you are potentially opening a file filenames.csv inside a subdirectory of your initial directory. You can run something like find . -name filenames.csv from your terminal, and you'll see plenty of filenames.csv. You can change this behavior by passing no_chdir option to find:

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

    (and additionally changing > for >> in your open)

    However, personally, I'd avoid repeatedly opening and closing filenames.csv when you could open it just once before calling find. If you don't want to have your filehandle globally defined, you can always pass it as an argument to findAllFiles:

    { 
        open my $fh, '>', 'filenames.csv' or die "Failed to open 'filenames.csv': $!";
        find(sub { findAllFiles($fh) }, '.')
    }
    
    sub findAllFiles {
        my ($fh) = @_;
        ...