为什么Perl文件glob()在标量上下文中不在循环外工作?

时间:2010-04-13 21:44:12

标签: perl glob perl5.10

根据关于文件globbing的Perl文档,< *> operator或glob()函数在标量上下文中使用时,应遍历匹配指定模式的文件列表,每次调用时返回下一个文件名,或者当没有更多文件时返回undef。

但是,迭代过程似乎只能在循环中起作用。如果它不在循环中,那么它似乎在读取所有值之前立即重新开始。

来自Perl文档:

在标量上下文中,glob遍历此类文件名扩展,在列表耗尽时返回undef。

http://perldoc.perl.org/functions/glob.html

但是,在标量上下文中,操作符在每次调用时返回下一个值,或者在列表用完时返回undef。

http://perldoc.perl.org/perlop.html#I/O-Operators

示例代码:

use warnings;
use strict;

my $filename;

# in scalar context, <*> should return the next file name
# each time it is called or undef when the list has run out

$filename = <*>;
print "$filename\n";
$filename = <*>;      # doesn't work as documented, starts over and
print "$filename\n";  # always returns the same file name
$filename = <*>;
print "$filename\n";

print "\n";

print "$filename\n" while $filename = <*>; # works in a loop, returns next file
                                           # each time it is called

在包含3个文件... file1.txt,file2.txt和file3.txt的目录中,上面的代码将输出:

file1.txt
file1.txt
file1.txt

file1.txt
file2.txt
file3.txt

注意:实际的perl脚本应该位于测试目录之外,否则您也会在输出中看到脚本的文件名。

我在这里做错了什么,或者这是怎么回事?

4 个答案:

答案 0 :(得分:9)

这是一种将<> glob运算符状态的魔法捕获到一个对象中的方法,你可以用正常的方式操作它:anonymous subs(和/或closures)!

sub all_files {
    return sub { scalar <*> };
}

my $iter = all_files();
print $iter->(), "\n";
print $iter->(), "\n";
print $iter->(), "\n";

或者也许:

sub dir_iterator {
    my $dir = shift;
    return sub { scalar glob("$dir/*") };
}
my $iter = dir_iterator("/etc");
print $iter->(), "\n";
print $iter->(), "\n";
print $iter->(), "\n";

然后我再次倾向于在“好奇心”下提出这个问题。忽略glob() / <>的这种特殊怪异,并使用opendir / readdirIO::All / readdirFile::Glob代替: )

答案 1 :(得分:5)

以下代码似乎也创建了2个独立的迭代器实例......

for ( 1..3 )
{
   $filename = <*>;
   print "$filename\n" if defined $filename;
   $filename = <*>;
   print "$filename\n" if defined $filename;
}

我想我看到那里的逻辑,但它与文档有点反直觉和矛盾。文档没有提到必须处于循环中以使迭代工作的任何事情。

答案 2 :(得分:3)

同样来自perlop

  

(文件)glob仅在启动新列表时评估其(嵌入)参数。

调用glob会创建一个列表,该列表要么全部返回(在列表上下文中),要么一次检索一个元素(在标量上下文中)。但每次调用glob都会创建一个单独的列表。

答案 3 :(得分:0)

(抓住我对Perl的生锈记忆......)我认为<*>的多个词法实例被视为glob的独立invokations,而在while循环中你调用相同的“实例”(无论那意味着什么)。

想象一下,例如,如果你这样做了:

while (<*>) { ... }
...
while (<*>) { ... }

你当然不希望这两次调用相互干扰。