Why does calling this function change my array?

Perl seems to kill 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"; 

gives:

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

but when I comment on func() , it gives what I would expect:

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

Any ideas why this could be happening?

+4
source share
2 answers

You must change foo to localize $_ or not use $_ in your loop. Best of all, 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: $!"; } 

Foreach loop aliases $_ to the current file name and while(<READ>) assigns $_ . This is a bad combination of magic, so to speak.

All in all, it’s a bad idea to rely on a lot of $_ for something other than single line.

+12
source

It should have been a comment on Leon's answer, but I have no reputation so far; My apologies.

Minor error: $ filename should also replace $ _ in the body of the foreach loop.

Minor nitpick: I would advise always using the three forms of the open argument using a lexical file descriptor, 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"; 
+3
source

All Articles