Home > Back-end >  How can I scan a filehandle twice to copy it based on its contents?
How can I scan a filehandle twice to copy it based on its contents?

Time:04-13

My overall perl script is trying to operate as follows:

  • Read source file for content
  • Find regex match and use that match for Destination filename
  • Open new Destination filename
  • Find regex match for C format comments /* */ that contain a keyword, i.e. abcd
  • Write string matches found to destination filename
#!/usr/bin/perl
use warnings;
use strict;

my $src = 'D:\\Scripts\\sample.c';
my $fileName;

# open source file for reading
open(SRC,'<',$src) or die $!;

while(my $row = <SRC>){
    if ($row =~ /([0-9]{2}\.[0-9]{2}\.[0-9]{3}\.[a-z,0-9]{2}|[0-9]{2}\.[0-9]{2}\.[0-9]{3}\.[a-z,0-9]{3})/){
        $fileName = $1;
    }
}

my $des = "D:\\Scripts\\" . $fileName . ".txt";

# open destination file for writing
open(DES,'>',$des) or die $!;

print("copying content from $src to $des\n");

while(my $row = <SRC>){
    if ($row =~ /(\/\*.*abcd.[\s\S]*?\*\/)/){
        print DES $1;
    }
}

# always close the filehandles
close(SRC);

close(DES);
print "File content copied successfully!\n";

I am running this in Windows 10 command line with Perl 5.32.1. My problem is I am not getting any content writing to the destination file. The file gets created but no content gets written to it. When I change:

print DES $1; -> print "$1\n";

I get no content coming out the command line window either. When I move the entire second if statement to be nested underneath the first while loop after the 1st if statement I get output to the command line. But I cannot keep the 2nd if statement there because I want it to write to the destination file.

CodePudding user response:

As the $src file is read the first time the SRC filehandle reaches the file end. So when you try to read the file again, there is nothing to read on that filehandle (and it won't tell).

After the first read is done reposition the filehandle to the beginning of the file

seek SRC, 0, 0;

There are nice symbolic constants that can be used with seek, see Fcntl

Another option is to close and open the file again. (Or even just re-open the same filehandle to it, in which case it gets closed first.)


Note: it is just better to use lexical filehandles than typeglobs, like

open my $src_fh, '<', $src_file  or die $!;

See a comment on it in perldata, and search SO posts (here is one for example).

CodePudding user response:

I'd change the problem slightly. Instead of reading the file twice, read it once. Write to a temp file where the name is not important. Along the way, discover the final filename. After you are done, rename the temp file.

  • Related