【发布时间】:2012-08-15 17:34:29
【问题描述】:
在 Java7 中,sun.nio.fs.Globs 和 getPathMatcher() 似乎将成语 ** 理解为一种跨目录边界匹配零个或多个字符的方法(请参阅the getPathMatcher javadoc)。
我可以发誓一些壳牌(zsh,bash,tcsh),一些适当的选项设置在某些时候给了我相同的行为。但是对于我的一生,我不记得如何启用它,我什至开始怀疑我的记忆是否我在某个时候让它工作......(编辑:zsh 提供了这种行为,但仅适用于目录,即@ 987654325@ 不匹配 foo/bar/fubar.gz,但 "**/*.gz" 匹配)。
事实上,查看各种 glob 实现的文档(例如 POSIX glob(3)、glob(7) 和 Perl 的 File::Glob)似乎并没有在任何地方提及这种行为。一个例外是 Ruby 的 Dir.glob(),它显式处理 **。
(最初的问题是:“有人知道如何在 unix shell(例如 zsh)中启用此行为吗?”,但现在请参阅下面的已编辑问题)。
作为一个额外的问题:有人知道如何在 Google 中搜索 '**' 吗?...
已编辑的问题
事实上,我的zsh shell 似乎确实接受了这种行为(感谢断言这一事实并促使我进一步研究的回复)。我认为它不是来自以下微妙之处的原因:"**.gz" 不会匹配 <path>/<prefix>.gz,但 "**/*.gz" 会。这是一个例子。让我们从以下树开始:
$ find . -type f | sort
./foo/a.gz
./foo/bar/fubar/abc.gz
./foo/bar/x.gz
./foo/bar/y.gz
./xyz.gz
"**.gz" 在子目录中不匹配,只匹配 "*.gz" 会:
$ ls -1 **.gz
xyz.gz
而"**/*.gz" 会:
$ ls -1 **/*.gz
foo/a.gz
foo/bar/fubar/abc.gz
foo/bar/x.gz
foo/bar/y.gz
xyz.gz
现在,将其与 Java 行为进行比较:
@Test
public void testStar() {
String pat = Globs.toUnixRegexPattern("*.gz");
assertEquals("^[^/]*\\.gz$", pat);
}
@Test
public void testStarStar() {
// '**' allows any number of directories on the path
// this apparently is not POSIX, although darn useful
String pat = Globs.toUnixRegexPattern("**.gz");
assertEquals("^.*\\.gz$", pat);
}
很明显(来自正则表达式),这里的"**" 匹配路径上的任何字符(即它在正则表达式中变为".*"),无论是否在子目录中,以及是否作为文件名的一部分。
(免责声明:Globs 是 sun.nio.fs.Globs.toUnixRegexPattern(String glob) 的副本,因为我需要跨平台的东西)。
【问题讨论】:
-
zsh 具有
**递归通配特性。据我所知,它默认启用。您必须使用setopt extendedglob来开启一些额外的通配功能,但这不是其中之一。 -
好吧,它对我不起作用。我一定是无意中禁用了它。在充满 *.png 的目录和带有 *.png 的子目录中,
echo *.png | wc -w和echo **.png | wc -w只给出相同的结果。我试过extendedglob,但正如你提到的,它不会影响行为。 -
它的 zsh 版本不能完全那样工作。
**匹配任意数量的目录,但要匹配最后的文件,您必须单独指定它。echo **/*.png