如何从 Perl 文件句柄中读取数组元素?
我很快写下了一个 Perl 脚本,该脚本可以仅用数字列对几个文件进行平均。它涉及从文件句柄数组中读取。这是脚本:
#!/usr/local/bin/perl
use strict;
use warnings;
use Symbol;
die "Usage: $0 file1 [file2 ...]\n" unless scalar(@ARGV);
my @fhs;
foreach(@ARGV){
my $fh = gensym;
open $fh, $_ or die "Unable to open \"$_\"";
push(@fhs, $fh);
}
while (scalar(@fhs)){
my ($result, $n, $a, $i) = (0,0,0,0);
while ($i <= $#fhs){
if ($a = <$fhs[$i]>){
$result += $a;
$n++;
$i++;
}
else{
$fhs[$i]->close;
splice(@fhs,$i,1);
}
}
if ($n){ print $result/$n . "\n"; }
}
这不起作用。如果我调试脚本,在初始化 @fhs 后,它看起来像这样:
DB<1> x @fhs
0 GLOB(0x10443d80)
-> *Symbol::GEN0
FileHandle({*Symbol::GEN0}) => fileno(6)
1 GLOB(0x10443e60)
-> *Symbol::GEN1
FileHandle({*Symbol::GEN1}) => fileno(7)
到目前为止,一切都很好。但它在我尝试从文件中读取的部分失败:
DB<3> x $fhs[$i]
0 GLOB(0x10443d80)
-> *Symbol::GEN0
FileHandle({*Symbol::GEN0}) => fileno(6)
DB<4> x $a
0 'GLOB(0x10443d80)'
$a 填充了这个字符串,而不是从 glob 中读取的内容。我做错了什么?
I quickly jotted off a Perl script that would average a few files with just columns of numbers. It involves reading from an array of filehandles. Here is the script:
#!/usr/local/bin/perl
use strict;
use warnings;
use Symbol;
die "Usage: $0 file1 [file2 ...]\n" unless scalar(@ARGV);
my @fhs;
foreach(@ARGV){
my $fh = gensym;
open $fh, $_ or die "Unable to open \"$_\"";
push(@fhs, $fh);
}
while (scalar(@fhs)){
my ($result, $n, $a, $i) = (0,0,0,0);
while ($i <= $#fhs){
if ($a = <$fhs[$i]>){
$result += $a;
$n++;
$i++;
}
else{
$fhs[$i]->close;
splice(@fhs,$i,1);
}
}
if ($n){ print $result/$n . "\n"; }
}
This doesn't work. If I debug the script, after I initialize @fhs it looks like this:
DB<1> x @fhs
0 GLOB(0x10443d80)
-> *Symbol::GEN0
FileHandle({*Symbol::GEN0}) => fileno(6)
1 GLOB(0x10443e60)
-> *Symbol::GEN1
FileHandle({*Symbol::GEN1}) => fileno(7)
So far, so good. But it fails at the part where I try to read from the file:
DB<3> x $fhs[$i]
0 GLOB(0x10443d80)
-> *Symbol::GEN0
FileHandle({*Symbol::GEN0}) => fileno(6)
DB<4> x $a
0 'GLOB(0x10443d80)'
$a is filled with this string rather than something read from the glob. What have I done wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您只能在
<>
中使用简单的标量变量来读取文件句柄。<$foo>
有效。<$foo[0]>
不从文件句柄读取;它实际上相当于glob($foo[0])
。您必须使用内置的readline
临时变量,或使用 IO::File 和 OO 表示法。如果您没有从循环内的数组中删除元素,则可以通过将
while
循环更改为foreach
循环来轻松使用临时变量。就我个人而言,我认为使用 gensym 来创建文件句柄是一个丑陋的黑客行为。您应该使用 IO::File,或者将未定义的变量传递给
open
(这至少需要 Perl 5.6.0,但现在已经有近 10 年历史了)。 (只需说my $fh;
而不是my $fh = gensym;
,Perl 就会自动创建一个新的文件句柄并将其存储在$fh
中> 当你调用open
时。)You can only use a simple scalar variable inside
<>
to read from a filehandle.<$foo>
works.<$foo[0]>
does not read from a filehandle; it's actually equivalent toglob($foo[0])
. You'll have to use thereadline
builtin, a temporary variable, or use IO::File and OO notation.If you weren't deleting elements from the array inside the loop, you could easily use a temporary variable by changing your
while
loop to aforeach
loop.Personally, I think using
gensym
to create filehandles is an ugly hack. You should either use IO::File, or pass an undefined variable toopen
(which requires at least Perl 5.6.0, but that's almost 10 years old now). (Just saymy $fh;
instead ofmy $fh = gensym;
, and Perl will automatically create a new filehandle and store it in$fh
when you callopen
.)如果您愿意使用一点魔法,您可以非常简单地做到这一点:
除非您使用的是非常旧的 Perl,否则没有必要使用
gensym
。 IIRC、perl 5.6 及更新版本对正常的词法句柄感到满意:open my $fh, '<', 'foo';
If you are willing to use a bit of magic, you can do this very simply:
Unless you are using a very old perl, the messing about with
gensym
is not necessary. IIRC, perl 5.6 and newer are happy with normal lexical handles:open my $fh, '<', 'foo';
我很难理解你的逻辑。您想读取多个仅包含数字(每行一个数字)的文件并打印其平均值吗?
I have trouble understanding your logic. Do you want to read several files, which just contains numbers (one number per line) and print its average?
似乎
for
循环更适合您,您实际上可以在其中使用标准读取(迭代)运算符。看起来您根本不想缩短循环。因此,
while
似乎是错误的循环习惯用法。Seems like a
for
loop would work better for you, where you could actually use the standard read (iteration) operator.It doesn't look like you want to shortcut the loop at all. Therefore,
while
seems to be the wrong loop idiom.