Perl glob returning a false positive

对着背影说爱祢 提交于 2019-12-20 05:54:53

问题


What seemed liked a straightforward piece of code most certainly didn't do what I wanted it to do.

Can somebody explain to me what it does do and why?

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";
}

In my test case, the directory did exist and it was empty. However, the then (first) section of the if triggered instead of the else section as expected.

I don't need anybody to suggest how to accomplish what I want to accomplish. I just want to understand Perl's interpretation of this code, which definitely does not match mine.


回答1:


Using glob (aka <filepattern>) in a scalar context makes it an iterator; it will return one file at a time each time it is called, and will not respond to changes in the pattern (e.g. a different $dir) until it has finished iterating over the initial results; I suspect this is causing the trouble you see.

The easy answer is to always use it in list context, like so:

if( -d $dir && ( () = <$dir/*> ) ) {

glob may only really be used safely in scalar context in code you will execute more than once if you are absolutely sure you will exhaust the iterator before you try to start a new iteration. Most of the time it's just easier to avoid glob in scalar context altogether.




回答2:


I believe that @ysth is on the right track, but repeated calls to glob in scalar context don't generate false positives.

For example

use strict;
use warnings;
use 5.010;

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

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

output

/usr/bin

/usr/bin

But what is true is that any single call to glob maintains a state, so if I have

use strict;
use warnings;
use 5.010;

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

output

/sys/block

/sys/bus

/sys/class

/sys/dev

So clearly that glob statement inside the loop is maintaining a state, and ignoring the changes to $dir.

This is similar to the way that the pos (and corresponding \G regex anchor) has a state per scalar variable, and how print without a specific file handle prints to the last selected handle. In the end it is how all of Perl works, with the it variable $_ being the ultimate example.



来源:https://stackoverflow.com/questions/26920291/perl-glob-returning-a-false-positive

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!