Reputation: 33
I'm new to Perl and I have a problem when reading a file line by line. I started with a tutorial which suggested using a while loop. That worked fine, however I wanted to have an option to break out of the loop in case of an error. I know I can use the "last" keyword, but I don't like that very much, I would like to include it in the while loop's boolean expression so it is easier to see on what conditions it stops. So I did
$error=0;
while ( (!$error) && (<MYFILE>) ) {
print $_;
...
}
Unfortunately, this doesn't work because $_ seems to contain a "uninitialized value". For some reason, when I change (!$error) to (!0), it works again. I would understand that it was not working had I used || because of lazy evaluation, but with && in this case both sides need to be evaluated so I don't understand why it doesn't initialize the line variable.
Upvotes: 2
Views: 10439
Reputation: 1509
First, as Jonathan points out you should always write languages idiomatically unless you have a very good reason and here you don't.
Your larger problem is misunderstanding the while
loop. The automatic assignment of the result of the angle operator to $_
only occurs if it is the only thing in the while
conditional test. If there are multiple items in the conditional test they are evaluated and then discarded (Programming Perl pp. 80-81 and I/O Operators at Perldoc).
Upvotes: 3
Reputation: 755064
The magical assignment to $_
only occurs if there is nothing else in the loop:
while (<MYFILE>) {
print $_;
...
}
If you want the error test too - which is not recommended - then you need to do the assignment:
my $error = 0;
while (!$error && ($_ = <MYFILE>)) {
print;
$error = 1 if m/quit/i;
}
Don't forget to add:
use warnings;
use strict;
The reason why the version with '!0
' worked is probably because Perl optimizes and recognizes that '!0
' is always true and removes it from the loop, leaving just the I/O operator, which then assigns to $_
.
NB: it is far better to use idiomatic Perl and the last
statement:
while (<MYFILE>) {
print;
last if m/quit/i;
}
Upvotes: 5