Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I use the diamond operator with an array in Perl?

Code

$ cat test1
hello 
i am 
lazer

nananana
$ cat 1.pl
use strict;
use warnings;

my @fh;
open $fh[0], '<', 'test1', or die $!;

my @res1 = <$fh[0]>;  # Way1: why does this not work as expected?
print @res1."\n"; 

my $fh2 = $fh[0];
my @res2 = <$fh2>;    # Way2: this works!
print @res2."\n";

Run

$ perl 1.pl
1
5
$

I am not sure why Way1 does not work as expected while Way2 does. Aren't those two methods the same? What is happening here?

like image 789
Lazer Avatar asked Nov 29 '10 15:11

Lazer


4 Answers

Because of the dual nature of the <> operator (i.e. is it glob or readline?), the rules are that to behave as readline, you can only have a bareword or a simple scalar inside the brackets. So you'll have to either assign the array element to a simple scalar (as in your example), or use the readline function directly.

like image 140
runrig Avatar answered Nov 01 '22 23:11

runrig


Because from perlop:

If what's within the angle brackets is neither a filehandle nor a simple scalar variable containing a filehandle name, typeglob, or typeglob reference, it is interpreted as a filename pattern to be globbed, and either a list of filenames or the next filename in the list is returned, depending on context. This distinction is determined on syntactic grounds alone. That means <$x> is always a readline() from an indirect handle, but <$hash{key}> is always a glob().

You can spell the <> operator as readline instead to avoid problems with this magic.

like image 35
hobbs Avatar answered Nov 01 '22 21:11

hobbs


Anything more complex than a bareword (interpreted as a file handle) or a simple scalar $var is interpreted as an argument to the glob() function. Only barewords and simple scalars are treated as file handles to be iterated by the <...> operator.

Basically the rules are:

<bareword> ~~  readline bareword
<$scalar>  ~~  readline $scalar
<$array[0]> ~~ glob "$array[0]"
<anything else> ~~ glob ...
like image 33
Eric Strom Avatar answered Nov 01 '22 22:11

Eric Strom


It's because <$fh[0]> is parsed as glob($fh[0]).

Use readline instead:

my @res1 = readline($fh[0]);
like image 22
Eugene Yarmash Avatar answered Nov 01 '22 21:11

Eugene Yarmash