SSh
SSh

Reputation: 189

Why am I getting an uninitialized value warning when reading two lines at a time?

I am trying to read two lines at a time with a while loop but am getting this error:

line    1
line    2
line    3
Use of uninitialized value in concatenation (.) or string at ....
Use of uninitialized value in concatenation (.) or string at ....
Use of uninitialized value in concatenation (.) or string at ....

Script:

#!/usr/bin/perl 
use warnings;
use strict;

my $count = 1;
while ( my $two_lines = <DATA> . <DATA> ) {
    print $two_lines;
}


__DATA__
line    1
line    2
line    3

Upvotes: 0

Views: 231

Answers (4)

Brad Gilbert
Brad Gilbert

Reputation: 34120

What you may not be aware of is that

while ( my $line = <DATA> ){ ... }

is short for

while ( defined( my $line = <DATA> ) ){ ... }

That transformation only occurs for simple constructs like that.

If it didn't check for definedness then it could skip the last line if it contained nothing but 0.
( the other lines are guaranteed to have a line separator as well, so they would continue to work correctly. )


A way to get it to work similarly for one or two lines at a time is:

# take advantage of the built-in transformation
while ( my $two_lines = <DATA> ) {
  $two_lines .= <DATA> // '';

  ... # your code here
}

Upvotes: 0

Dustin
Dustin

Reputation: 360

It's not really an error, its just a warning. You should get 2 warnings on even line number files, and 3 warnings on odd numbered files. When it comes through the while expression the first time, it reads from the first time fine, then when it reads the second time, the filehandle is empty, and it prints the warning. Because it returned something the first time, it will execute the contents of the while loop. the last time, it will evaluate the filestream twice, get nothing and abort the loop, but warn both times it tries to concaticate the empty reads. If you need a while loop i would do

while ( my $first_lines = <DATA> ) {
    if (my $second_line = <DATA> ){
         print $first_lines . $second_line;
    }else{
        print $first_lines
        break;
    }
}

Upvotes: 2

ikegami
ikegami

Reputation: 385789

readline aka <$fh> returns undef to signal the end of the file (or an error). You're not checking for that. Fix:

while (1) {
   defined( my $line1 = <DATA> )
      or last;
   defined( my $line2 = <DATA> )
      or die("Premature end of file\n");

   print($line1 . $line2);
}

Upvotes: 1

mob
mob

Reputation: 118605

The readline operator <HANDLE> returns undef when reading from an exhausted filehandle (in scalar handle). So the first warning comes in the 2nd iteration of the while loop when you read the (missing) 4th line from DATA. The next two warnings come from the 3rd iteration, when you call <DATA> twice on an exhausted filehandle.

You can fix this by using an expression that will not be undef. Since you're using perl >=v5.16, you can use

while (my $line = (<DATA> // '') . (<DATA> // '')) { ...

Upvotes: 3

Related Questions