Bash 扩展 Globbing

作者: Mitch Frazier

bash 中的通配符被称为路径名扩展。路径名扩展有时也被称为 globbing。当您在命令中输入 "*"、"?" 和 "[...]" 语法时,路径名扩展会“扩展”它们,例如

  $ ls *.jpg         # List all JPEG files
  $ ls ?.jpg         # List JPEG files with 1 char names (eg a.jpg, 1.jpg)
  $ rm [A-Z]*.jpg    # Remove JPEG files that start with a capital letter
关于路径名扩展的一个微妙但常常被忽略的点是,它是由 bash 完成的而不是由操作系统或正在运行的程序完成的。程序永远看不到通配符,bash 在运行程序之前将扩展结果替换到命令行中。只有在编写代码并调用 exec() 及其朋友时,这一点才显得重要:如果您不通过 bash 执行程序,则传递给 exec() 的命令行中的任何通配符都不会被扩展。

但这些并非 bash 支持的唯一的通配符形式。其他形式被称为扩展 globbing,您必须先启用它们才能使用它们

  $ shopt -s extglob
bash 手册页中描述的扩展 globbing
  ?(pattern-list)   Matches zero or one occurrence of the given patterns
  *(pattern-list)   Matches zero or more occurrences of the given patterns
  +(pattern-list)   Matches one or more occurrences of the given patterns
  @(pattern-list)   Matches one of the given patterns
  !(pattern-list)   Matches anything except one of the given patterns
这里的模式列表是由竖线“|”(也称为管道符号)分隔的项目列表。如果你看一下这些,你就会明白为什么选择前导字符,因为它与正则表达式语法中使用的字符相匹配
  Bash              Regular Expression
  ?(pattern-list)   (...|...)?
  *(pattern-list)   (...|...)*
  +(pattern-list)   (...|...)+
  @(pattern-list)   (...|...)    [@ not a RE syntax]
  !(pattern-list)   "!" used as for negative assertions in RE syntax
好吧,除了“@”字符,你就能明白为什么了……

例如,要列出所有以“ab”或“def”开头的 JPEG 和 GIF 文件,您可以这样做

  $ ls +(ab|def)*+(.jpg|.gif)
当然,您也可以在不使用扩展 globbing 的情况下执行此操作
  # ls ab*.jpg ab*.gif def*.jpg def*.gif

要列出所有与正则表达式“ab(2|3)+.jpg”匹配的文件,您可以这样做

  $ ls ab+(2|3).jpg
这是使用常规 globbing 无法实现的。注意:这匹配诸如 ab2.jpg、ab3.jpg、ab2222.jpg、ab333.jpg 等文件。

但是,可能最有趣的扩展 globbing 语法是“!(...)”语法,用于匹配除(即不匹配)以外的所有内容。但是,请注意,这并不总是按您期望的方式工作。例如,让我们列出所有不是 JPEG 或 GIF 的文件。人们首先想到的可能是这样的

  $ ls *!(.jpg|.gif)         # wrong, Wrong, WRONG
但这不起作用,因为任何文件名的“.jpg”和“.gif”最终都会被“*”匹配,并且文件名末尾的空字符串最终会匹配“!(...)”模式。正确的语法是
  $ ls !(*.jpg|*.gif)

对于一个更复杂的否定示例,让我们回到第一个例子,列出所有不是 JPEG 或 GIF 文件并且以“ab”或“def”开头的文件。这实际上非常简单,我们只需将第一个示例嵌套在“!(...)”中

  $ ls !(+(ab|def)*+(.jpg|.gif))
当然,就像复杂的正则表达式一样,写完 10 分钟后,这将完全无法理解。

Mitch Frazier 是艾默生电气公司的嵌入式系统程序员。自 2000 年代初以来,Mitch 一直是Linux Journal的撰稿人和朋友。

加载 Disqus 评论