这个脚本:
#!/usr/bin/perl
use strict;
use warnings;
my ${fh};
open($fh, '<', "some_file.txt") or die "fail\n";
while(my $line = <${fh}> ) {
print $line;
}
close $fh;
输出:
GLOB(0x5bcc2a0)
为什么这是输出?
如果我将<${fh}>
更改为<$fh>
,则会按预期逐行打印some_file.txt
。我认为大括号可用于分隔变量名称,my ${var}
与my $var
相同。
是否存在在变量名称周围添加{}
会导致问题的其他情况?
我在Red Hat和Cygwin Perl 5.14上尝试过Perl 5.8.8。
答案 0 :(得分:18)
来自perlop中<>
的部分:
如果尖括号包含的是一个简单的标量变量(例如,
$foo
),那么该变量包含要输入的文件句柄的名称,或其typeglob,或对其的引用。例如:$fh = \*STDIN; $line = <$fh>;
如果尖括号内的内容既不是文件句柄也不是包含文件句柄名称,typeglob或typeglob引用的简单标量变量,则它被解释为要进行全局化的文件名模式,以及文件名列表或者返回列表中的下一个文件名,具体取决于上下文。这种区别仅仅是出于句法原因而确定的。这意味着
<$x>
始终是间接句柄的readline()
,但<$hash{key}>
始终是glob()
。这是因为$x
是一个简单的标量变量,但$hash{key}
不是 - 它是一个哈希元素。即使<$x >
(请注意额外空格)也会被视为glob("$x ")
,而不是readline($x)
。
您可以使用B::Concise:
查看此信息$ perl -MO=Concise -e'<$fh>'
5 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 1 -e:1) v:{ ->3
4 <1> readline[t1] vK*/1 ->5
- <1> ex-rv2sv sK/1 ->4
3 <$> gvsv(*fh) s ->4
-e syntax OK
$ perl -MO=Concise -e'<${fh}>'
6 <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 70 -e:1) v:{ ->3
5 <@> glob[t1] vK/1 ->6
- <0> ex-pushmark s ->3
- <1> ex-rv2sv sK/1 ->4
3 <$> gvsv(*fh) s ->4
4 <$> gv(*_GEN_0) s ->5
-e syntax OK
答案 1 :(得分:11)
<>
表示readline(ARGV)
<IDENTIFIER>
表示readline(IDENTIFIER)
<$IDENTIFIER>
表示readline($IDENTIFIER)
<...>
(其他任何内容)表示glob(qq<...>)
所以,
<$fh>
表示readline($fh)
<${fh}>
表示glob(qq<${fh}>)
,与glob("$fh")
相同。 glob
用于从模式生成许多字符串或文件名。
在这种情况下,文件句柄的字符串化为GLOB(0x5bcc2a0)
。这被传递给glob,但这些字符都没有glob
的特殊含义,因此glob
只返回该字符串。