为什么 Perl 的 glob() 函数总是 return 给定一个没有通配字符的字符串时的文件名?
Why does Perl's glob() function always return a file name when given a string with no globbing characters?
我向 Perl 的 glob
函数提供了一个 glob 列表和一个字符串。 globs 被按预期处理,但始终找到字符串。例如:
$ ls
foo
$ perl -le '@files=glob("*bar"); print @files' ## prints nothing, as expected
$ perl -le '@files=glob("bar"); print @files'
bar
正如您在上面看到的,第二个示例打印 bar
,即使不存在这样的文件。
我的第一个想法是,它的行为类似于 shell,因为当没有扩展可用时,一个 glob(或被视为 glob 的东西)会扩展到自身。例如,在 csh
中(尽管很糟糕,这就是 Perl 的 glob()
函数似乎遵循的内容,请参阅下面的引用):
% foreach n (*bar*)
foreach: No match.
% foreach n (bar)
foreach? echo $n
foreach? end
bar ## prints the string
然而,根据 the docs,glob
应该 return 文件名扩展(强调我的):
In list context, returns a (possibly empty) list of filename expansions on the value of EXPR such as the standard Unix shell /bin/csh would do.
那么,当传递给 glob
的参数中没有通配符时,为什么它会 return 自身?这是一个错误还是我做错了什么?
当您使用 ?
或 *
或 []
时,只会返回现有的文件或目录。当您的模式只有文字文本或 {}
时,将返回所有可能的结果。这与 csh 所做的完全一致。
通常,人们会因此 @results = grep -e, glob PATTERN
这样做。
或者,如果您想对此进行更多控制,可以使用 File::Glob::bsd_glob。 (请注意,这样做没有额外的开销;因为当您使用 glob() perl 5.6 时,perl 会安静地加载 File::Glob 并使用它。)
I guess I expected Perl to be checking for file existence in the background.
Perl 是检查文件是否存在:
$ strace perl -e'glob "foo"' 2>&1 | grep foo
execve("/home/mcarey/perl5/perlbrew/perls/5.24.0-debug/bin/perl", ["perl", "-eglob \"foo\""], [/* 39 vars */]) = 0
lstat("foo", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
So why is it returning itself when there are no globbing characters in the argument passed to glob?
因为这就是 csh 的作用。 Perl 的 glob
实现基于启用了 GLOB_NOMAGIC
标志的 glob(3):
GLOB_NOMAGIC
Is the same as GLOB_NOCHECK but it only appends the pattern if it does not contain any of the special characters *
, ?
or [
. GLOB_NOMAGIC is provided to simplify implementing the historic csh(1) globbing behavior and should probably not be used anywhere else.
GLOB_NOCHECK
If pattern does not match any pathname, then glob() returns a list consisting of only pattern...
因此,对于像 foo
这样没有通配符的模式:
- 如果存在匹配文件,则文件名扩展 (
foo
) returned
- 如果不存在匹配文件,模式 (
foo
) 是 returned
由于文件名扩展与模式相同,
glob 'foo'
在列表上下文中总是 return 一个包含单个元素 foo
的列表,无论文件 foo
是否存在。
我向 Perl 的 glob
函数提供了一个 glob 列表和一个字符串。 globs 被按预期处理,但始终找到字符串。例如:
$ ls
foo
$ perl -le '@files=glob("*bar"); print @files' ## prints nothing, as expected
$ perl -le '@files=glob("bar"); print @files'
bar
正如您在上面看到的,第二个示例打印 bar
,即使不存在这样的文件。
我的第一个想法是,它的行为类似于 shell,因为当没有扩展可用时,一个 glob(或被视为 glob 的东西)会扩展到自身。例如,在 csh
中(尽管很糟糕,这就是 Perl 的 glob()
函数似乎遵循的内容,请参阅下面的引用):
% foreach n (*bar*)
foreach: No match.
% foreach n (bar)
foreach? echo $n
foreach? end
bar ## prints the string
然而,根据 the docs,glob
应该 return 文件名扩展(强调我的):
In list context, returns a (possibly empty) list of filename expansions on the value of EXPR such as the standard Unix shell /bin/csh would do.
那么,当传递给 glob
的参数中没有通配符时,为什么它会 return 自身?这是一个错误还是我做错了什么?
当您使用 ?
或 *
或 []
时,只会返回现有的文件或目录。当您的模式只有文字文本或 {}
时,将返回所有可能的结果。这与 csh 所做的完全一致。
通常,人们会因此 @results = grep -e, glob PATTERN
这样做。
或者,如果您想对此进行更多控制,可以使用 File::Glob::bsd_glob。 (请注意,这样做没有额外的开销;因为当您使用 glob() perl 5.6 时,perl 会安静地加载 File::Glob 并使用它。)
I guess I expected Perl to be checking for file existence in the background.
Perl 是检查文件是否存在:
$ strace perl -e'glob "foo"' 2>&1 | grep foo
execve("/home/mcarey/perl5/perlbrew/perls/5.24.0-debug/bin/perl", ["perl", "-eglob \"foo\""], [/* 39 vars */]) = 0
lstat("foo", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
So why is it returning itself when there are no globbing characters in the argument passed to glob?
因为这就是 csh 的作用。 Perl 的 glob
实现基于启用了 GLOB_NOMAGIC
标志的 glob(3):
GLOB_NOMAGIC
Is the same as GLOB_NOCHECK but it only appends the pattern if it does not contain any of the special characters
*
,?
or[
. GLOB_NOMAGIC is provided to simplify implementing the historic csh(1) globbing behavior and should probably not be used anywhere else.GLOB_NOCHECK
If pattern does not match any pathname, then glob() returns a list consisting of only pattern...
因此,对于像 foo
这样没有通配符的模式:
- 如果存在匹配文件,则文件名扩展 (
foo
) returned - 如果不存在匹配文件,模式 (
foo
) 是 returned
由于文件名扩展与模式相同,
glob 'foo'
在列表上下文中总是 return 一个包含单个元素 foo
的列表,无论文件 foo
是否存在。