I usually loop through lines in a file using the following code:
open my $fh, '<', $file or die "Could not open file $file for reading: $!\n";
while ( my $line = <$fh> ) {
...
}
However, in answering another question, Evan Carroll edited my answer, changing my while
statement to:
while ( defined( my $line = <$fh> ) ) {
...
}
His rationale was that if you have a line that's 0
(it'd have to be the last line, else it would have a carriage return) then your while
would exit prematurely if you used my statement ($line
would be set to "0"
, and the return value from the assignment would thus also be "0"
which gets evaluated to false). If you check for defined-ness, then you don't run into this problem. It makes perfect sense.
So I tried it. I created a textfile whose last line is 0
with no carriage return on it. I ran it through my loop and the loop did not exit prematurely.
I then thought, "Aha, maybe the value isn't actually 0
, maybe there's something else there that's screwing things up!" So I used Dump()
from Devel::Peek
and this is what it gave me:
SV = PV(0x635088) at 0x92f0e8
REFCNT = 1
FLAGS = (PADMY,POK,pPOK)
PV = 0X962600 "0"\0
CUR = 1
LEN = 80
That seems to tell me that the value is actually the string "0"
, as I get a similar result if I call Dump()
on a scalar I've explicitly set to "0"
(the only difference is in the LEN field -- from the file LEN is 80, whereas from the scalar LEN is 8).
So what's the deal? Why doesn't my while()
loop exit prematurely if I pass it a line that's only "0"
with no carriage return? Is Evan's loop actually more defensive, or does Perl do something crazy internally that means you don't need to worry about these things and while()
actually only does exit when you hit eof
?
Because
while (my $line = <$fh>) { ... }
actually compiles down to
while (defined( my $line = <$fh> ) ) { ... }
It may have been necessary in a very old version of perl, but not any more! You can see this from running B::Deparse on your script:
>perl -MO=Deparse
open my $fh, '<', $file or die "Could not open file $file for reading: $!\n";
while ( my $line = <$fh> ) {
...
}
^D
die "Could not open file $file for reading: $!\n" unless open my $fh, '<', $file;
while (defined(my $line = <$fh>)) {
do {
die 'Unimplemented'
};
}
- syntax OK
So you're already good to go!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With