Perl glob返回假阳性

时间:2014-11-13 23:18:31

标签: perl glob

看起来很简单的一段代码肯定没有做我想做的事情。

有人可以向我解释它的作用和原因吗?

my $dir = './some/directory';

if ( -d $dir && <$dir/*> ) {
    print "Dir exists and has non-hidden files in it\n";
}
else {
    print "Dir either does not exist or has no non-hidden files in it\n";
}

在我的测试用例中,目录确实存在且为空。但是,then的{​​{1}}(第一)部分已按预期触发,而不是if部分。

我不需要任何人建议如何完成我想要完成的任务。我只想了解Perl对此代码的解释,这绝对不符合我的。

2 个答案:

答案 0 :(得分:4)

在标量上下文中使用glob(又名<filepattern>)使其成为迭代器;它将在每次调用时一次返回一个文件,并且在完成对初始结果的迭代之前不会响应模式中的更改(例如,不同的$ dir);我怀疑这会导致你看到麻烦。

简单的答案是始终在列表上下文中使用它,如下所示:

if( -d $dir && ( () = <$dir/*> ) ) {
如果你绝对确定你会在尝试开始新的迭代之前耗尽迭代器,那么<​​p> glob可能只能在代码中的标量上下文中安全地使用。大多数情况下,在标量上下文中完全避免使用glob更容易。

答案 1 :(得分:1)

我认为@ysth处于正确的轨道,但在标量上下文中重复调用glob 会产生误报。

例如

use strict;
use warnings;
use 5.010;

say scalar glob('/usr/*'), "\n";

say scalar glob('/usr/*'), "\n";

<强>输出

/usr/bin

/usr/bin

但是 是什么 任何单个调用glob维持一个状态,所以如果我有

use strict;
use warnings;
use 5.010;

for my $dir ( '/sys', '/usr', '/sys', '/usr' ) {
  say scalar glob("$dir/*"), "\n";
}

<强>输出

/sys/block

/sys/bus

/sys/class

/sys/dev

很明显,循环中的glob语句维持状态,忽略对$dir的更改。

这类似于pos(和相应的\G正则表达式锚点)具有每个标量变量的状态的方式,以及没有特定文件句柄的print如何打印到< em>最后选择的句柄。最后,它是所有Perl的工作方式, it 变量$_是最终的例子。