简体   繁体   中英

Why is @ARGV undefined inside this Perl one-liner?

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?

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 .

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}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM