How can I know if diamond operator moved to the next file?

465 Views Asked by At

I have the following code in a file perl_script.pl:

while (my $line = <>) {
    chomp $line;
   // etc. 
}. 

I call the script with more than 1 file e.g.

perl perl_script.pl file1.txt file2.txt

Is there a way to know if the $line is started to read from file2.txt etc?

3

There are 3 best solutions below

0
zdim On BEST ANSWER

The $ARGV variable

Contains the name of the current file when reading from <>

and you can save the name and test on every line to see if it changed, updating when it does.

If it is really just about getting to a specific file, as the question seems to say, then it's easier since you can also use @ARGV, which contains command-line arguments, to test directly for the needed name.


One other option is to use eof (the form without parenthesis!) to test for end of file so you'll know that the next file is coming in the next iteration -- so you'll need a flag of some sort as well.

A variation on this is to explicitly close the filehandle at the end of each file so that $. gets reset for each new file, what normally doesn't happen for <>, and then $. == 1 is the first line of a newly opened file

while (<>) { 
    if ($. == 1) { say "new file: $ARGV" }
} 
continue { 
    close ARGV if eof;
} 
0
hobbs On

A useful trick which is documented in perldoc -f eof is the } continue { close ARGV if eof } idiom on a while (<>) loop. This causes $. (input line number) to be reset between files of the ARGV iteration, meaning that it will always be 1 on the first line of a given file.

1
brian d foy On

There's the eof trick, but good luck explaining that to people. I usually find that I want to do something with the old filename too.

Depending on what you want to do, you can track the filename you're working on so you can recognize when you change to a new file. That way you know both names at the same time:

use v5.10;
my %line_count;
my $current_file = $ARGV[0];
while( <> ) {
    if( $ARGV ne $current_file ) {
        say "Change of file from $current_file to $ARGV";
        $current_file = $ARGV;
        }

    $line_count{$ARGV}++
    }

use Data::Dumper;
say Dumper( \%line_count );

Now you see when the file changes, and you can use $ARGV

Change of file from cache-filler.pl to common.pl
Change of file from common.pl to wc.pl
Change of file from wc.pl to wordpress_posts.pl
$VAR1 = {
          'cache-filler.pl' => 102,
          'common.pl' => 13,
          'wordpress_posts.pl' => 214,
          'wc.pl' => 15
        };

Depending what I'm doing, I might not let the diamond operator do all the work. This give me a lot more control over what's happening and how I can respond to things:

foreach my $arg ( @ARGV ) {
    next unless open my $fh, '<', $arg;
    while( <$fh> ) { 
        ...
        }
    }