【问题标题】:When is ** understood by file glob()?文件 glob() 什么时候理解**?
【发布时间】:2012-08-15 17:34:29
【问题描述】:

在 Java7 中,sun.nio.fs.GlobsgetPathMatcher() 似乎将成语 ** 理解为一种跨目录边界匹配零个或多个字符的方法(请参阅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);
}

很明显(来自正则表达式),这里的"**" 匹配路径上的任何字符(即它在正则表达式中变为".*"),无论是否在子目录中,以及是否作为文件名的一部分。

(免责声明:Globssun.nio.fs.Globs.toUnixRegexPattern(String glob) 的副本,因为我需要跨平台的东西)。

【问题讨论】:

  • zsh 具有** 递归通配特性。据我所知,它默认启用。您必须使用setopt extendedglob 来开启一些额外的通配功能,但这不是其中之一。
  • 好吧,它对我不起作用。我一定是无意中禁用了它。在充满 *.png 的目录和带有 *.png 的子目录中,echo *.png | wc -wecho **.png | wc -w 只给出相同的结果。我试过extendedglob,但正如你提到的,它不会影响行为。
  • 它的 zsh 版本不能完全那样工作。 ** 匹配任意数量的目录,但要匹配最后的文件,您必须单独指定它。 echo **/*.png

标签: shell glob


【解决方案1】:

POSIX shell:

路径名中的斜杠字符应通过使用显式匹配 图案中的一个或多个斜线;它不应与 星号或问号特殊字符或括号 表达

你可以谷歌:“文件名扩展模式”。

在 bash 中你可以设置globstar:

[星号] 匹配任何字符串,包括空字符串。当 globstar shell 选项已启用,‘*’ 用于文件名扩展上下文, 两个相邻的‘*’s 用作单个模式将匹配所有文件和 零个或多个目录和子目录。如果后跟一个“/”,则两个 相邻的‘*’s 将只匹配目录和子目录。

$ shopt -s globstar
$ ls **/
$ shopt -u globstar
$ ls **/

注意:这里使用“/”仅显示目录。

【讨论】:

    【解决方案2】:

    ** 在 Zsh 的扩展 glob 语法中被解释为 (*/)#(零个或多个目录),它是在 Zsh 特定的 C 代码 (Src/glob.c) 中实现的。此行为不是可选的。

    shopt -s globstar 在 Bash 中启用时,它在 Bash 的扩展 glob 语法中的作用类似,该语法在 Bash 特定的 C 代码 (pathexp.c) 中实现。默认关闭。

    在传统的 UNIX glob 中,** 的解释与 * 相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-16
      • 2011-12-08
      • 2014-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多