5

I have a problem with looping through file names, my input array elements gets deleted.

CODE:

use Data::Dumper;
use warnings;
use strict;


my @files = ("file1", "file2", "file3");

print Dumper(\@files);

for (@files) {
        my $filename = $_ . '.txt';
        open(my $fh, '<:encoding(UTF-8)', $filename)
          or die "Could not open file '$filename' $!";
        while(<$fh>) {
                print "$filename read line \n";
        }
}
print Dumper(\@files);

OUTPUT:

$VAR1 = [
          'file1',
          'file2',
          'file3'
        ];
file1.txt read line
file2.txt read line
file3.txt read line
$VAR1 = [
          undef,
          undef,
          undef
        ];

FILE CONTENTS:

 cat file1.txt
asdfsdfs
 cat file2.txt
iasdfasdsf
 cat file3.txt
sadflkjasdlfj

Why does the array contents get deleted? (I have 2 different workarounds for the problem, but I would like to understand what's the problem with this code.)

gmezos
  • 53
  • 3

2 Answers2

7
while (<$fh>)

is short for

while ($_ = <$fh>)

so you are clobbering $_ which is aliased to an element of @files. You need to protect $_ as follows:

while (local $_ = <$fh>)

Better yet, use a different variable name.

while (my $line = <$fh>)
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • I also found that solution here: https://perldoc.perl.org/perlop.html#I%2fO-Operators Thanks! – gmezos Apr 15 '19 at 14:25
4

You're using $_ in two different ways inside of the loop (as the current filename and as the current line) and they're clobbering each other. Don't do this. Name your variables, e.g.:

for my $file (@files) {
    ...
    while(my $line = <$fh>) {
        ...
    }
}

You can imagine that your current code does this after reading each file:

for (@files) {
   undef $_;
}
AKHolland
  • 4,435
  • 23
  • 35
  • That was my workaround too. The other is to slurp the file into an array with @lines = <$fh>. Thanks. – gmezos Apr 15 '19 at 14:12