10

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

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

来自 Perl 文档:

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

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

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

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

示例代码:

使用警告;
使用严格;

我的$文件名;

# 在标量上下文中,<*> 应该返回下一个文件名
# 每次调用它或当列表用完时取消定义

$文件名 = <*>;
打印“$文件名\n”;
$文件名 = <*>; # 不像记录的那样工作,重新开始
打印“$文件名\n”;# 总是返回相同的文件名
$文件名 = <*>;
打印“$文件名\n”;

打印“\n”;

print "$filename\n" while $filename = <*>; # 循环工作,返回下一个文件
                                           # 每次调用

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

文件1.txt
文件1.txt
文件1.txt

文件1.txt
文件2.txt
文件 3.txt

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

我在这里做错了什么,还是它应该如何工作?

4

4 回答 4

9

这是一种将<>glob 运算符状态的魔力捕获到可以以正常方式操作的对象的方法:匿名子(和/或闭包)!

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代替:)

于 2010-04-13T23:57:32.413 回答
5

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

对于 ( 1..3 )
{
   $文件名 = <*>;
   如果已定义 $filename,则打印 "$filename\n";
   $文件名 = <*>;
   如果已定义 $filename,则打印 "$filename\n";
}

我想我看到了那里的逻辑,但这有点违反直觉并且与文档相矛盾。文档没有提到任何关于必须在循环中才能使迭代工作的内容。

于 2010-04-13T22:30:22.210 回答
3

也来自perlop

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

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

于 2010-04-13T22:22:52.590 回答
0

(擦掉我对 Perl 的生疏记忆......)我认为多个词汇实例<*>被视为 glob 的独立调用,而在 while 循环中,您调用的是相同的“实例”(无论这意味着什么)。

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

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

您当然不会期望这两个调用会相互干扰。

于 2010-04-13T21:58:25.633 回答