EpiMan
EpiMan

Reputation: 839

reading and printing a text file in Perl

I have simple question:

why the first code does not print the first line of the file but the second one does?

#! /usr/bin/perl

use warnings;
use strict;

my $protfile = "file.txt";
open (FH, $protfile);
while (<FH>) {
         print (<FH>);

}

#! /usr/bin/perl

use warnings;
use strict;

my $protfile = "file.txt";
open (FH, $protfile);
while (my $file = <FH>) {
         print ("$file");

}

Upvotes: 2

Views: 12154

Answers (4)

while (<FH>) {
    print (<FH>);
}

use this instead:

while (<FH>) {
    print $_;
}

Upvotes: 1

aschepler
aschepler

Reputation: 72463

When used in scalar context, <FH> returns the next single line from the file.

When used in list context, <FH> returns a list of all remaining lines in the file.

while (my $file = <FH>) is a scalar context, since you're assigning to a scalar. while (<FH>) is short for while(defined($_ = <FH>)), so it is also a scalar context. print (<FH>); makes it a list context, since you're using it as argument to a function that can take multiple arguments.

while (<FH>) {
    print (<FH>);
}

The while part reads the first line into $_ (which is never used again). Then the print part reads the rest of the lines all at once, then prints them all out again. Then the while condition is checked again, but since there are now no lines left, <FH> returns undef and the loop quits after just one iteration.

while (my $file = <FH>) {
    print ("$file");
}

does more what you probably expect: reads and then prints one line during each iteration of the loop.

By the way, print $file; does the same as print ("$file");

Upvotes: 2

JB.
JB.

Reputation: 42154

Context.

Your first program tests for end-of-file on FH by reading the first line, then reads FH in list context as an argument to print. That translates to the whole file, as a list with one line per item. It then tests for EOF again, most likely detects it, and stops.

Your second program iterates by line, each one read in scalar context to variable $file, and prints them individually. It detects EOF by a special case in the while syntax. (see the code samples in the documentation)

So the specific reason why your program doesn't print the first line in one case is that it's lost in the argument to while. Do note that the two programs' structure is pretty different: the first only runs a single while iteration, while the second iterates once per line.

PS: nowadays, the recommended way to manage files tends towards lexical filehandles (open my $file, 'name'; print <$file>;).

Upvotes: 5

user2493235
user2493235

Reputation:

Because you are comsuming the first line with the <> operator and then using it again in the print, so the first line has already gone but you are not printing it. <> is the readline operator. You need to print the $_ variable, or assign it to a defined variable as you are doing in the second code. You could rewrite the first:

print;

And it would work, because print uses $_ if you don't give it anything.

Upvotes: 3

Related Questions