为什么@ARGV在这个Perl单行内部未定义?

时间:2012-01-02 16:42:48

标签: perl

他的END街区中的一个Stackoverflower tried to use @ARGV,但无法进行。

为什么@ARGV仅在BEGIN块内定义,并带有以下单行:

$ perl -lne 'BEGIN{ print "BEGIN"  if @ARGV }
                    print "MIDDLE" if @ARGV }
                  { print "END"    if @ARGV  ' file
  BEGIN

perldoc perlrun没有说明这件事。这是怎么回事?

2 个答案:

答案 0 :(得分:5)

首先,数组不能未定义。您正在检查数组是否为空。要了解它被清空的原因,您需要了解-n-n使用

围绕您的代码
LINE: while (<>) {
   ...
}

的缩写
LINE: while (defined($_ = <ARGV>)) {
   ...
}

ARGV是一个神奇的句柄,可以读取@ARGV中列出的文件,在打开文件名时将其移出。

$ 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:

请记住,BEGIN块一经编译就会执行,因此<ARGV>块在执行BEGIN块时尚未执行(即使它出现在程序的早期版本中),因此@ARGV尚未修改。

perlrun中记录了

-nARGV中记录了@ARGV$ARGV和{{1}}。

答案 1 :(得分:4)

BEGIN块先于其他任何方式运行。那时,@ ARGV已经传递了所有内容,并且非空虚的测试返回true。当END块运行时,原始@ARGV的元素已被'-n'开关生成的隐式while(&lt;&gt;){...}循环移走。由于没有任何东西,空的@ARGV测试为false。将END块更改为:

{print "END" if defined @ARGV}

当@ARGV的每个元素移位时,它存储在$ ARGV中。因此,该块也可以被重写:

{print "END" if $ARGV}