在this question中查看行为时,我惊讶地发现perl lstat()
的每个路径都与glob模式匹配:
$ 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)
和<pattern>
以及更高版本的perl看到了相同的行为。
我的期望是,globbing只是opendir / readdir,并且不需要检查它正在搜索的实际路径名。
这个lstat
的目的是什么?它会影响glob()的返回吗?
答案 0 :(得分:8)
这种奇怪的行为一直是noticed before on PerlMonks。事实证明,glob
调用lstat
来支持其GLOB_MARK
标志,其效果是:
作为与模式匹配的目录的每个路径名都附加了斜杠。
要确定目录条目是否引用了一个子目录,您需要stat
它。即使没有给出旗帜,这显然已经完成了。
答案 1 :(得分:3)
我想知道同样的事情 - “这个lstat的目的是什么?它会影响glob()的返回吗?”
在bsd_glob.c glob2()中,我注意到在if分支中需要设置GLOB_MARK标志的g_stat调用,我还注意到在没有被标志检查保护之前调用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中的测试5:
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中的测试5是
# 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)'
我不再看到dir中每个文件的lstat调用。 我并不是说建议对glob(File-Glob)的perl测试是全面的(它们不是),或者像这样的更改不会破坏现有的 行为(这似乎很可能)。据我所知,这个(g_l)stat调用的代码存在于原始-bsd / lib / libc / gen / glob.c中,24年前的1990年。
另见: