以下摘录代码在 perl 5.16.3 及更早版本上运行时,具有奇怪的行为,其中对行输入运算符中的 glob 的后续调用会导致 glob 继续返回以前的值,而不是重新运行 glob。
#!/usr/bin/env perl
use strict;
use warnings;
my @dirs = ("/tmp/foo", "/tmp/bar");
foreach my $dir (@dirs) {
my $count = 0;
my $glob = "*";
print "Processing $glob in $dir\n";
while (<$dir/$glob>) {
print "Processing file $_\n";
$count++;
last if $count > 0;
}
}
如果你放入两个文件/tmp/foo以及其中的一个或多个/tmp/bar,并运行代码,我得到以下输出:
处理 /tmp/foo 中的*
处理文件/tmp/foo/foo.1
在 /tmp/bar 中处理*
处理文件/tmp/foo/foo.2
我以为当while
后终止last
,新调用while
在第二次迭代中将重新运行 glob 并给我列出的文件/tmp/bar,但我得到了内容的延续/tmp/foo.
这几乎就像角度运算符 glob 的作用就像预编译模式一样。我的假设是角度运算符正在符号表中创建一个文件句柄,该文件句柄仍然打开并在幕后重用,并且它的范围仅限于包含foreach
,或者可能是整个子例程。
From perlop 中的 I/O 运算符 http://perldoc.perl.org/perlop.html#I/O-Operators(我的重点)
(文件)glob 仅在启动时才评估其(嵌入)参数
新列表。在重新开始之前必须读取所有值。在列表中
上下文,这并不重要,因为你会自动获取它们
反正。但是,在标量上下文中,运算符返回下一个值
每次被调用时,或者undef
当列表用完时。
Since <>
在这里在标量上下文中调用,然后使用以下命令退出循环last
第一次迭代后,下次输入时,它会继续从原始列表中读取。
评论中澄清了这一任务背后的实际需求:仅处理目录中的某些文件,并且从不返回所有文件名因为可能有很多。
所以分配自glob
到一个列表并使用它,或者更好的是使用for
代替while
正如评论者ysth https://stackoverflow.com/users/17389/ysth,在这里没有帮助,因为它返回一个巨大的列表。
我还没有找到方法glob
(what <>
使用文件名模式)一旦生成列表,就删除并重建列表,而无需先到达其末尾。
显然,操作符的每个实例都有自己的列表。所以使用另一个<>
在 - 的里面while
循环并希望以任何方式重置它,即使使用相同的模式,也不会影响正在迭代的列表while (<$glob>)
.
只是要注意,用 a 打破循环die
(with while
in an eval
)也没有帮助;下次我们再讨论这个问题时while
同样的清单还在继续。将其包裹在封闭物中
sub iter_glob { my $dir = shift; return sub { scalar <"$dir/*"> } }
for my $d (@dirs) {
my $iter = iter_glob($d);
while (my $f = $iter->()) {
# ...
}
}
遭遇同样的命运;原始列表继续使用。
那么解决方案是使用readdir
反而。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)