为什么glob lstat匹配条目?

7

研究这个问题中的行为时,我惊讶地发现perl lstat()会遍历匹配通配符模式的每个路径:

$ mkdir dir
$ touch dir/{foo,bar,baz}.txt  
$ strace -e trace=lstat perl -E 'say $^V; <dir/b*>' 
v5.10.1
lstat("dir/baz.txt", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
lstat("dir/bar.txt", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0

我在我的Linux系统上使用glob(pattern)和

@mpapec,我下次在终端时会更新我的期望,谢谢。 - pilcrow
只是一个提示:在我的系统上,我不得不将“lstat”更改为“lstat64”。 - choroba
2个回答

8
这种奇怪的行为以前在PerlMonks上被注意到过。原来glob调用lstat来支持其GLOB_MARK标志,这会导致以下效果:

与模式匹配的每个目录路径名都会附加一个斜杠。

要找出目录条目是否指向子目录,需要对其进行stat。即使没有给出标志,这似乎也会执行。


3

我也在想同样的问题 - "lstat的目的是什么?它会影响glob()的返回结果吗?"

在bsd_glob.c中的glob2()函数内,我注意到有一个g_stat调用,需要设置GLOB_MARK标志,我还注意到在此之前有一个g_lstat调用,它没有被标记检查保护。这两个调用都在一个if分支内,用于处理模式结束的情况。 如果我在perl-5.12.4/ext/File-Glob/bsd_glob.c的glob2函数中移除这两行代码...

- if (g_lstat(pathbuf, &sb, pglob))
-     return(0);

唯一不通过的Perl测试(make test)是在ext/File-Glob/t/basic.t内的第五个测试,出现了以下错误:

not ok 5
#   Failed test at ../ext/File-Glob/t/basic.t line 92.
#     Structures begin differing at:
#          $got->[0] = 'asdfasdf'
#     $expected->[0] = Does not exist

t/basic.t中的第五个测试是

# check nonexistent checks
# should return an empty list
# XXX since errfunc is NULL on win32, this test is not valid there
@a = bsd_glob("asdfasdf", 0);
SKIP: {
    skip $^O, 1 if $^O eq 'MSWin32' || $^O eq 'NetWare';
    is_deeply(\@a, []);
}

如果我用以下内容替换掉被删除的2行代码:
+   if (!((pglob->gl_flags & GLOB_NOCHECK) ||
+         ((pglob->gl_flags & GLOB_NOMAGIC) &&
+          !(pglob->gl_flags & GLOB_MAGCHAR)))){
+     if (g_lstat(pathbuf, &sb, pglob))
+       return(0);
+   }

我在使用linux x86_64 (RHEL6.3 2.6.32-358.11.1.el6.x86_64)和以下命令时,没有看到perl-5.12.4的"make test"失败:

strace -fe trace=lstat perl -e 'use File::Glob q{:glob};
                               print scalar bsd_glob(q{/var/log/*},GLOB_NOCHECK)'

我不再看到每个目录中的文件的lstat调用。

我的意思并不是说perl测试glob(File-Glob)是全面的(它们不是),或者这样的更改不会破坏现有行为(这似乎很可能)。就我所知,具有此(g_l)stat调用的代码存在于1990年的original-bsd / lib / libc / gen / glob.c中,已经有24年了。

另请参阅:

  • “精通Perl”的第6章“Perl基准测试”,作者Brian D Foy,Randal L. Schwartz,其中包含一个比较使用glob()和opendir()的代码部分。
  • 来自Dick Dunn的1991年comp.unix.wizards“未来Globs(名为“UNIX mindset ...”)”
  • Usenet新闻组mod.sources Guido van Rossum在1986年7月发布了“Globbing”库例程(glob) - 我没有在该代码中看到“stat”的参考。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接