<>
operator applying to readline
and glob
functionality, and the special behavior of while
in checking if their return value is defined rather than checking if is true, goes back to the history of Perl using csh
for globbing...
<>
operator applying to readline
and glob
functionality, and the special behavior of while
in checking if their return value is defined rather than checking if is true, goes back to the history of Perl using csh
for globbing...
csh
for globbing, or that the developers wanted to make it so that it would behave as though it had been implemented that way.
6> open my $f, 'fortune | cowthink |'; $res[4] = 32514 7> while (<$f>) { print "*** $_" } *** ________________________________________ *** ( Anyone who understands everything that ) *** ( comes out of fortune probably has a ) *** ( problem ) *** ---------------------------------------- *** o ^__^ *** o (oo)\_______ *** (__)\ )\/\ *** ||----w | *** || || $res[5] = '' 8> close $f;
<$f>
is a filehandle read (it is itself syntactic sugar for readline $f
), while (<$f>)
has the special behavior of checking if the result of that filehandle read is defined, which is to say that it behaves similarly to while (defined <$f>)
. Though not relevant to your specific question, it would be very confusing if I didn't mention that, really, it is not syntactic sugar for that, because it is also assigning the value to $_
.
while (<$f>) { print "*** $_" }
causes to be used could almost be written like this (or maybe exactly, but I am not 100% sure on the specific scoping rules for $_
when it is implicitly assigned in a loop):
<$f>
or even my $_ = <$f>
, but is defined(my $_ = <$f>)
. That expression returns false.
my
is not the kind of scoping that automatically assigned $_
uses.
ek@Io:~$ perl -we 'open my $f, q{fortune | }; while (<$f>) { print; last } print "[$_]\n"' Oh, the Slithery Dee, he crawled out of the sea. [Oh, the Slithery Dee, he crawled out of the sea. ]
ek@Io:~$ perl -we 'open my $f, q{fortune | }; while (my $line = <$f>) { print $line; last } print "[$line]\n"' Name "main::line" used only once: possible typo at -e line 1. "You are old," said the youth, "and your jaws are too weak Use of uninitialized value $line in concatenation (.) or string at -e line 1, <$f> line 1. []
$_
gets reset when you from an inner nested loop that uses it implicitly to an outer nested loop that uses it implicitly, but they are apparently not implemented by giving $_
any special scoping. I will have to look into that. Anyway, the whole thing about the variable is not directly germane to your question.
perldoc perlop
and go down to the I/O Operators section, one of the (many) things it says is:
The following lines are equivalent: while (defined($_ = <STDIN>)) { print; } while ($_ = <STDIN>) { print; } while (<STDIN>) { print; } for (;<STDIN>;) { print; } print while defined($_ = <STDIN>); print while ($_ = <STDIN>); print while <STDIN>;
while
(when used this way, and more generally too, in a slightly weaker sense):
while
loop is the return value of the built-in defined
function. That's the last expression to be evaluated. The final time <$f>
is evaluated, it returns undef
, but when that is passed to defined
, you get false, which reply
shows as ''
.
reply
displays a false scalar value, when that false value is capable of being readily taken to be of any dynamic type, as is the case of false values that are generated by most Perl expressions to signify falsity.
The various logical operators don't return an empty string, they return a false or true value in all three simple scalar types. It just looks like it returns an empty string because print forces a string context on its arguments: #!/usr/bin/perl use strict; use warnings; use Devel::Peek; my ...
undef
return value from the filehandle read to the defined
operator, which return a generic false value. That generic false value is then shown as ''
, even though it is not really the empty string any more than it is really, for example 0
.
''
but also really the default value of the other dynamic types a scalar can be. The way Perl lets you often not worry about whether something is, say, a number or a string, is to keep track of whether or not it has a computed value of each of the possible dynamic types that is current, and what a (possibly current) value is for each of them (when there is something that might be current).
$_
is replaced after the loop in which it is implicitly assigned ends.
2> for (1..3) { print "---\nOuter: $_\n"; for (11..13) { print "Inner: $_\n" } print "Outer: $_\n" } --- Outer: 1 Inner: 11 Inner: 12 Inner: 13 Outer: 1 --- Outer: 2 Inner: 11 Inner: 12 Inner: 13 Outer: 2 --- Outer: 3 Inner: 11 Inner: 12 Inner: 13 Outer: 3 $res[2] = '' 3> for (1..3) { print "---\nOuter: $_\n"; while (glob '1{1,2,3}') { print "Inner: $_\n" } print "Outer: $_\n" } --- Outer: 1 Inner: 11 Inner: 12 Inner: 13 Use of uninitialized value $_ in concatenation (.) or string at reply input line 1.
perldoc perlop
means when it says, "The $_
variable is not implicitly localized. You'll have to put a "local $_;" before the loop if you want that to happen." More fully, talking about how to use the <>
operator in scalar context to read the next line from a filehandle, it says:
Ordinarily you must assign the returned value to a variable, but there is one situation where an automatic assignment happens. If and only if the input symbol is the only thing inside the conditional of a "while" statement (even if disguised as a "for(;;)" loop), the value is automatically assigned to the global variable $_, destroying whatever was there previously. (This may seem like an odd thing to you, but you'll use the construct in almost every Perl script you write.) The $_ variable is not implicitly localized. You'll have to put a "local $_;" before the loop
ek@Io:~$ reply 0> open my $f, '>', 'foo'; $res[0] = 1 1> print {$f} "first line of foo\nsecond line of foo\n"; $res[1] = 1 2> close $f; $res[2] = 1 3> open my $f, '>', 'bar'; $res[3] = 1 4> print {$f} "first line of bar\nsecond line of bar\nthird line of bar\n"; $res[4] = 1 5> close $f; $res[5] = 1 6> open my $f, '>', 'baz'; $res[6] = 1 7> print {$f} "first line of baz\nsecond line of baz\n"; $res[7] = 1 8> close $f; $res[8] = 1 9> exit ek@Io:~$ cat foo first line of foo second line of foo
<>
is that command-line arguments, unless they are interpreted as arguments to perl
(i.e., the Perl interpreter) itself, are placed automatically in the array @ARGV
, before the script's code is run. The first time you read <>
, that array is consulted. Arguments from that array are used as the filename. If there are no arguments, it is as if a single -
arguments had been passed, causing standard input to be read from.
open
is used, so special behavior that causes perl
do to stuff other than just open files occurs. (Notice that I've used the three-argument version, except when I used the two-argument version with |
, which is part of its special syntax.) This has security implications, some but not all of which are mitigated when reading from <<>>
instead of <>
, but <<>>
is only supported in new versions of perl
.
ek@Io:~$ perl -we 'while (<>) { print "$ARGV: $_" }' foo bar baz foo: first line of foo foo: second line of foo bar: first line of bar bar: second line of bar bar: third line of bar baz: first line of baz baz: second line of baz ek@Io:~$ perl -we 'while (<>) { print "$ARGV: $_" }' <<<$'First\nSecond' -: First -: Second
ek@Io:~$ perl -we 'while (<>) { print "(@ARGV)\n\t$ARGV: $_" }' foo bar baz (bar baz) foo: first line of foo (bar baz) foo: second line of foo (baz) bar: first line of bar (baz) bar: second line of bar (baz) bar: third line of bar () baz: first line of baz () baz: second line of baz
@ARGV
(i.e., the filenames) are shifted off the beginning (with shift
) before being used.
ek@Io:~$ perl -we '@ARGV = qw(foo bar baz); while (<>) { print "$ARGV: $_" }' <<<$'First\nSecond' foo: first line of foo foo: second line of foo bar: first line of bar bar: second line of bar bar: third line of bar baz: first line of baz baz: second line of baz ek@Io:~$ perl -we 'while (<>) { print "$ARGV: $_" }' <<<$'First\nSecond' -: First -: Second
@ARGV
is modified before the first read of <>
, then the behavior of <>
is altered accordingly. One use of this is to process out command-line options before you then read from <>
process the remaining command-line arguments, which you assume to be filenames. For example:
#!/usr/bin/env perl use strict; use warnings; use Getopt::Long qw(GetOptions :config gnu_getopt no_auto_abbrev); my $verbose = 0; GetOptions('verbose|v' => \$verbose); while (<>) { if ($verbose) { print "$ARGV: " } print; }
ek@Io:~/pl$ ./opt-demo foo bar baz first line of bar second line of bar third line of bar first line of baz second line of baz ek@Io:~/pl$ ./opt-demo -v foo bar baz bar: first line of bar bar: second line of bar bar: third line of bar baz: first line of baz baz: second line of baz ek@Io:~/pl$ ./opt-demo foo --verbose bar -vv baz bar: first line of bar bar: second line of bar bar: third line of bar baz: first line of baz baz: second line of baz
Getopt::Long
, automatically remove options from @ARGV
as they process them. They even remove the operands for the options, if you define any non-medadic options. They leave non-option arguments (specifically, they leave arguments that neither specify options nor are operands of options), and those are used as filenames when reading with <>
.
<>
(or explicitly calling readline
with no argument) is using: it uses the special ARGV
filehandle, which provides the behavior of shifting filenames off @ARGV
and attempting to open and read from them in sequence. Writing <>
has the exact same effect as writing <ARGV>
.
-n
and -p
both work by enclosing the entire script that the interpreter receives, whether as a file being executed or as the contents of one or more arguments to the -e
or -E
option, to be enclosed implicitly in while (<>) { ... }
. That is, the script goes where I wrote ...
there. The -n
and -p
options differ in what additional code is taken implicitly to be present. The short summary of the difference is that -p
prints the line <>
read, after each iteration.