I recommend avoiding $_ for almost all situations. It was suppose to make your code more English like, but it really doesn't improve readability:
for ( @array ) {
next unless /^foo/;
print;
}
Is that really more readable than this?
for my $item ( @array ) {
next unless $item =~ /^foo/;
print "$item\n";
}
Nor, does it have any sort of magic properties (as Borodin hinted in his answer) that another variables would not have. Any variable, and not just $_ would be aliased to the element in a for loop. In this program, I change three to buzz in my array by simply changing the value of the variable $item:
use strict;
use warnings;
my @array = qw(one two three four five);
for my $item ( @array ) {
if ( $item eq "three" ) {
$item = "buzz"; # Will actually change $array[2]
}
}
#
# Let's print out my array and see if $array[2] got changed.
#
for my $item ( @array ) {
print "$item\n";
}
This prints out:
one
two
buzz
four
five
Even worse, $_ raises it's ugly head anyway in any loop longer than a few lines. In your example, you have:
my $fpname = $sdir . '/' . $_;
So much for being invisible.
In your example, you noticed that the value of $_ seems to keep working in both the inner and outer loop. That is, even though I'm using the same variable, somehow the two loops don't interfere with each other.
That's because $_ is localized for each loop. It's one of those Perl mishmash concepts that non-Perl developers rant and rave about.
$_ is the same variable in both loops. $_ is global in scope. However, in each loop, the value that this global variable contains is localized to the scope of the loop. Huh? See local and get ready to have your mind blown. It usually takes a few years for someone to learn the difference between a package (aka globally) scoped variable, a lexically (aka locally) scoped variable, and a package scoped (aka global) variable that's localized. No wonder why all the Python programmers make fun of me.
As ysth stated, although using $_ happens to work, your program is would be easier to understand if you used an actual variable in each loop. Besides, imagine what would happen if you had need the name of the file that the line came from in your while loop. (warnThe line $_ in file $_ is not in the right format";`).
You may want to use labels when you have loops within loops. A label can be used to tell which loop a next or last should be going to:
FILE:
for my $source_file ( @files ) {
open my $source_fh, "<", $source_file; # Use autodie...
LINE:
while ( my $line = <$file> ) {
...
...
next LINE if ... # Don't need this line
...
...
next FILE if ... # I'm done with this file
...
}
}
Even if you don't use next FILE like I did, a label simply makes your program a bit cleaner. You're not merely going to the next iteration of the loop, you're going to the next LINE of the file.
$_ *=2 for my @r =1..5; print "@r"so foreach variable($_) is here aliased to@rarray elements.