alisea
alisea

Reputation: 362

Unexpected behaviour of filehandle in conjunction with subroutine call - why?

I am reading a file line by line and want to process each line through a subroutine. Since I am not interested in the line itself, I put the read from the filehandle directly into the subroutine call. However, this leads to unexpected behaviour I don't quite understand.

I created a minimal example demonstrating the effect:

#!/usr/bin/perl

use strict;
use warnings;
use Carp;
use English qw( -no_match_vars );

print "This works as expected:\n";

open my $TEST1, '<', 'filetest1.txt' or croak "Can't open filetest1.txt - $ERRNO";          

my $line1 = <$TEST1>;
print_line( $line1 );

while ( 1 ) {
    last if eof $TEST1; 
    $line1 = <$TEST1>;
    print $line1;
}
close $TEST1;

print "\n";
print "Unexpected effect here:\n";
open my $TEST2, '<', 'filetest1.txt' or croak "Can't open filetest1.txt - $ERRNO";          

print_line(<$TEST2>); # this works, but just once

while ( 1 ) {
    last if eof $TEST2; # is triggered immediately
    print "This is never printed\n";
    print_line(<$TEST2>);
}
close $TEST2;

sub print_line {
    my $line = shift;
    print $line;
    return 1;
}

Content of filetest1.txt:

test line 1
test line 2
test line 3
test line 4
test line 5

Result of the script:

This works as expected:
test line 1
test line 2
test line 3
test line 4
test line 5
Unexpected effect here:
test line 1

It seems that when I read the next line directly in the subroutine call, it works exactly once and then eof is triggered. I haven't found any explanation for that effect, and it forces me to create the variable $line1 just to pass the line to the subroutine.

I'm looking for an explanation why that happens, and consequently I'd like to understand the limits of what I can or cannot do with a filehandle.

Upvotes: 3

Views: 62

Answers (2)

dgw
dgw

Reputation: 13646

In your code print_line(<$FH>); the reading from the filehandle will be will be done in wantarray-mode meaning you don't read a single line but the whole file. And in your subroutine you just use the first line and discard the rest. Thats why the filehandle is empty after your first loop encounter.

You could just provide the filehandle to the subroutine and read a line there:

open my $FH , '<' , 'somefile' or die "Cannot read: $!" ;
while( ! eof $FH ) {
  print_line( $FH ) ;
}

sub print_line {
  my ( $fh ) = @_ ;

  my $line = <$fh> ;
  print $line ;
}

Upvotes: 3

user3967089
user3967089

Reputation:

You have a context problem. The $TEST1 read is in scalar context, so it only read one line. The $TEST2 read is in list context, so all the lines from the file are read and print_line() is called with a list of them as its arguments. So the second time you try to read from $TEST2 you get EOF, since all the lines were read the first time.

Upvotes: 1

Related Questions