Why is @ARGV undefined inside this single-line Perl?

A friend of Stackoverflower tried to use @ARGV in his END block, but failed.

Why is it @ARGV defined only inside the BEGIN block with the following single-line:

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

perldoc perlrun does not shed light on this question. What's going on here?

+4
source share
2 answers

Firstly, arrays cannot be undefined. You check if the array is empty. To understand why it is empty, you need to understand -n . -n surrounds your code with

 LINE: while (<>) { ... } 

which is not enough for

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

ARGV is a magic descriptor that reads files listed in @ARGV , rearranging file names when they open 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, therefore <ARGV> is not executed yet when the BEGIN block is executed (even if it appears earlier in the program), therefore @ARGV has not yet been changed.

-n documented in perlrun . ARGV , @ARGV and $ARGV described in perlvar .

+5
source

The BEGIN block is the first to start. At this point, @ARGV has everything that is passed, and the non-empty test returns true. When the END block is executed, the elements of the original @ARGV are shifted by the implicit while (<>) {...} loop generated by the '-n' switch. Since there is nothing left, empty @ARGVs check false. Change the END block to:

 {print "END" if defined @ARGV} 

Since each @ARGV element is shifted, it is stored in $ ARGV. Therefore, the block can also be rewritten:

 {print "END" if $ARGV} 
+4
source

Source: https://habr.com/ru/post/1388958/


All Articles