为什么$ {fh}在逐行阅读时的行为与$ fh不同?

时间:2016-01-15 22:51:41

标签: perl

这个脚本:

#!/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。

2 个答案:

答案 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只返回该字符串。