Reputation: 37136
A fellow Stackoverflower tried to use @ARGV
in his END
block but was unable to.
Why is it that @ARGV
is only defined inside the BEGIN
block with the following one-liner:
$ perl -lne 'BEGIN{ print "BEGIN" if @ARGV }
print "MIDDLE" if @ARGV }
{ print "END" if @ARGV ' file
BEGIN
perldoc perlrun
doesn't shed any light on the matter. What's going on here?
Upvotes: 4
Views: 1439
Reputation: 385655
First, arrays cannot be undefined. You are checking if the array is empty. To understand why it's being emptied, you need to understand -n
. -n
surrounds your code with
LINE: while (<>) {
...
}
which is short for
LINE: while (defined($_ = <ARGV>)) {
...
}
ARGV
is a magical handle that reads through the files listed in @ARGV
, shifting out the file names as it opens them.
$ echo foo1 > foo
$ echo foo2 >>foo
$ echo bar1 > bar
$ echo bar2 >>bar
$ echo baz1 > baz
$ echo baz2 >>baz
$ perl -nlE'
BEGIN { say "Files to read: @ARGV" }
say "Read $_ from $ARGV. Files left to read: @ARGV";
' foo bar baz
Files to read: foo bar baz
Read foo1 from foo. Files left to read: bar baz
Read foo2 from foo. Files left to read: bar baz
Read bar1 from bar. Files left to read: baz
Read bar2 from bar. Files left to read: baz
Read baz1 from baz. Files left to read:
Read baz2 from baz. Files left to read:
Keep in mind that BEGIN
blocks are executed as soon as they are compiled, so the <ARGV>
hasn't yet been executed when the BEGIN
block is being executed (even though it appears earlier in the program), so @ARGV
hasn't been modified yet.
-n
is documented in perlrun. ARGV
, @ARGV
and $ARGV
are documented in perlvar.
Upvotes: 5
Reputation: 7516
A BEGIN block runs before anything else. At that point, @ARGV has everything being passed and a test for non-emptiness returns true. When the END block runs, the elements of the original @ARGV have been shifted away by the implicit while(<>) {...} loop generated by the '-n' switch. Since there is nothing left, the empty @ARGV tests false. Change the END block to:
{print "END" if defined @ARGV}
As each element of @ARGV is shifted, it is stored in $ARGV. Hence, the block could be also rewritten:
{print "END" if $ARGV}
Upvotes: 4