tags:

views:

275

answers:

2

Perl seems to be killing my array whenever I read a file:

my @files = ("foo", "bar", "baz");
print "Files: " . join(" ", @files) . "\n";

foreach(@files) {
   print "The file is $_\n";
   func();
}

sub func {
   open(READ, "< test.txt");
   while(<READ>) {
   }
   close READ;
}

print "Files: " . join(" ", @files) . "\n";

produces:

Files: foo bar baz
The file is foo
The file is bar
The file is baz
Files:

but when I comment out func(), it gives what I would've expected:

Files: foo bar baz
The file is foo
The file is bar
The file is baz
Files: foo bar baz

Any ideas why this might be happening?

+12  A: 

You have to change foo to localize $_, or not to use $_ in your loop. Best yet, do both:

foreach my $filename (@files) {
    print "The file is $filename\n";
    func();
}

sub func {
    local $_;
    open my $read, '<', 'test.txt' or die "Couldn't open test.txt: $!";
    while(<$read>) {
    }
    close $read or die "Couldn't close file: $!";
}

The foreach loop aliases $_ to the current name of the file and the while(<READ>) assigns to $_. That's a bad combination of magic, so to say.

In general, it's a bad idea to rely on much on $_ for anything other than a one-liner.

Leon Timmermans
my $_; (5.10+ only) is a better way to do it
ysth
True, but distributions are only beginning to move to 5.10. I assume people are still on 5.8 for the most part.
Leon Timmermans
I read that Ubuntu 8.10 uses Perl 5.10.
Brad Gilbert
Brad: that is correct, but personally I'm only using it since last week, so I'm not assuming other people are also using it. My Debian machines don't have it yet, for example. For that matter, plenty of people are still stuck on Perl 5.6 :-|.
Leon Timmermans
+3  A: 

This should have been a comment to Leon's answer, but I do not have the reputation yet; my apologies.

Minor bug: $filename should have replaced $_ in the body of the foreach loop, too.

Minor nitpick: I would advise to always use the three argument form of open using a lexical filehandle, even in short examples.

foreach my $filename (@files) {
    print "The file is $filename\n";
    func();
}

sub func {
   open my $read, '<', 'test.txt' or die $!;
   while(<$read>) {
   }
   close $read or die $!;
}

print 'Files: ' . join(' ', @files) . "\n";
fB
Minor bug: oops! Fixed it. You're right about that nitpick too.
Leon Timmermans