2

I got a problem with a Perl script.

Here is the code:

use strict;
use Data::Dumper;

my @data = ('a','b');

if(@data){
  for(@data){
    &debug_check($_)
  }
}

print "@data";#Nothing is printed, the array gets empty after the while loop.

sub debug_check{
  my $ip = shift;
  open my $fh, "<", "debug.txt";
  while(<$fh>){
    print "$_ $ip\n";
  }
}

Array data, in this example, has two elements. I need to check if the array has elements. If it has, then for each element I call a subroutine, in this case called "debug_check". Inside the subroutine I need to open a file to read some data. After I read the file using a while loop, the data array gets empty.

Why the array is being flushed and how do I avoid this strange behavior?

Thanks.

Carlitos_30
  • 371
  • 4
  • 13

2 Answers2

1

The problem here I think, will be down to $_. This is a bit of a special case, in that it's an alias to a value. If you modify $_ within a loop, it'll update the array. So when you hand it into the subroutine, and then shift it, it also updates @data.

Try:

my ( $ip ) = @_; 

Or instead:

for my $ip ( @array ) { 
     debug_check($ip);
}

Note - you should also avoid using an & prefix to a sub. It has a special meaning. Usually it'll work, but it's generally redundant at best, and might cause some strange glitches.

Sobrique
  • 52,974
  • 7
  • 60
  • 101
  • 3
    even if it weren't passed to the subroutine, the while loop (shorthand for `while ( defined( $_ = <$fh> ) )` would still be changing the array values (because the for aliases $_ to them). Using variables other than $_ in *both* the for loop and the while loop would be a good idea (though just changing the for fixes this problem) – ysth Dec 11 '14 at 19:08
  • Thanks very much. I just changed all default variables for defined ones. – Carlitos_30 Dec 11 '14 at 19:52
1
while (<$fh>)

is short for

while (defined($_ = <$fh>))

$_ is currently aliased to the element of @data, so your sub is replacing each element of @data with undef. Fix:

while (local $_ = <$fh>)

which is short for

while (defined(local $_ = <$fh>))

or

while (my $line = <$fh>)   # And use $line instead of $_ afterwards

which is short for

while (defined(my $line = <$fh>))

Be careful when using global variables. You want to localize them if you modify them.

ikegami
  • 367,544
  • 15
  • 269
  • 518