Whenever you find yourself wanting to type something like that, you
should really count to 10 and ask yourself what's more likely - that
there's a new and undiscovered bug in the language that's been used
worldwide for 20 years that you just happened to find, or that you
either did something wrong or don't understand the results you're
seeing.
This was tested with Perl 5.8.5 and 5.6.1
Test Program:
sub Foo() {
print "array_test: @array_test\n";
$shellcmd = "/bin/echo hi'";
open SHELLCMD, "$shellcmd |" or
die "Could not open shellcmd $!\n";
while (<SHELLCMD>) { } # do nothing - works with backticks not with shell
loop
close SHELLCMD;
print "array_test: @array_test\n";
}
@array_test = ("one");
for (@array_test) {
Foo();
}
Output:
array_test: one
array_test:
Why does array_test become unitialized?
It doesn't. The only element of @array_test, however does. If you'd
enabled warnings, you would see Perl tell you that you're printing an
undefined value, rather than printing no values. You could also
examine the contents of @array_test more precisely with the
Data:

umper module.
perldoc perlsyn
describes how for each loop works. When you don't give a loop
iterator variable, Perl localizes $_ and uses that. In your foreach
loop, $_ is an ALIAS to the element of the list you're iterating over,
meaning that changes to $_ will change the list itself.
In your subroutine, you are using $_ implicitly once more, this time
to iterate over the "/bin/echo hi |" shell command's output. In each
iteration of your while loop, $_ gets assigned to the current line of
output. When the output is exhausted, the readline operator (ie,
<SHELLCMD>) returns undef, and so $_ gets the value undef. But
remember that you've already aliased $_ to be the current element of
@array_test. So since you just changed $_, you've also changed the
current element of @array_test.
Yet if I add a loop variable for
@array_test ...
for $bar (@array_test) {
Foo();
}
It works:
Output:
array_test: one
array_test: one
Right, because this example doesn't use the localized $_, so the
function call doesn't get a chance to change your array elements.
Best practice - don't rely on the implicit nature of $_ for either for
loops nor while loops. If you must use $_, then localize it
beforehand. If you'd put the statement "local $_;" before you began
your while loop, you'd be working with a temporary value of $_ that
was not aliased to the foreach's list, and this "bug" would not have
appeared.
Paul Lalli
P.S. To help you see what's happening, please take a look at this
modified program, based off your example:
#!/usr/bin/perl
use strict;
use warnings;
use Data:

umper;
my @array_test;
sub Foo() {
print "array_test: ", Dumper(\@array_test);
my $shellcmd = "/bin/echo hi'";
open SHELLCMD, "$shellcmd |" or
die "Could not open shellcmd $!\n";
while (<SHELLCMD>) {
print "$. - ", Dumper(\@array_test);
}
close SHELLCMD;
print "array_test: ", Dumper(\@array_test);
}
@array_test = ("one");
for (@array_test) {
Foo();
}