双星号(**)通配符,也称为 globstar,是一种用于递归匹配子目录中文件的模式。它最早由 Zsh 在 1990 年代初引入,随后由 KornShell 在 2003 年独立实现并命名。最终,Bash 在 2009 年的 4.0 版本中采纳了这一特性,极大地推动了其普及。此后,** 演变为一个跨语言和工具的事实标准,被 Python、Ruby、JavaScript、Git 等广泛采用,简化了递归文件搜索的操作。
Globstar 的诞生:一个实用的创新
与只能在单个目录内匹配的星号(*)不同,双星号(**)是一个可以递归匹配多层子目录的通配符。例如,**/*.txt 会查找当前目录及其所有子目录下的全部 .txt 文件。
值得注意的是,这个功能并非源自最初的 Unix 设计,也没有被 POSIX 标准化。它是在不同的 Shell 和编程环境中作为扩展功能独立发展起来的。
Zsh:最早的先行者
Z shell(Zsh)是实现递归匹配的先驱。
- 早期实现: Zsh 在 1990 年左右引入了递归匹配的概念,并在 1992 年的 2.2 版本中确立了我们今天熟悉的
**/语法。 - 简化操作: 这一创新使得用户无需借助
find等外部工具,就能用简单的命令(如ls **/*.txt)列出所有子目录中的文件。 - 独特性: 在当时,传统的 Bourne shell、C shell 和早期的 Korn shell 都不具备此功能。
KornShell 与 “globstar” 的命名
大约十年后,KornShell(ksh93)也引入了类似的功能,但这是一个独立的实现。
- 独立发明: ksh93 在 2003 年左右添加了对
**的支持,并将其命名为 “globstar”。 - 命名来源: “globstar” 这个术语正是源于 ksh93 的这次实现。有趣的是,其作者 David Korn 当时并不知道 Zsh 早已实现了这个功能,他以为这是自己的原创。
我所知的是,当我在 2003 年添加它时,
**并不存在于其他 shell 中。 — David Korn, 2016
Bash 的普及之路
作为使用最广泛的 Shell,Bash 的采纳是 ** 走向主流的关键一步。
- 版本支持: Bash 在 2009 年发布的 4.0 版本中正式引入了该功能,并沿用了 KornShell 的名称
globstar。 - 默认禁用: 为了避免破坏依赖旧有行为的脚本,
globstar在 Bash 中默认是禁用的。你需要通过shopt -s globstar命令来手动开启。 - 巨大影响: Bash 的庞大用户基础使得
**模式迅速为广大开发者所熟知和使用。
从 Shell 到编程语言的演变
** 的简洁和实用性使其迅速超越了 Shell 的范畴,被各种编程语言和开发工具广泛采纳。
- Ruby: 是较早的支持者之一,其文件匹配方法
Dir.glob早在 2000 年代中期就已支持**语法。 - Python: 在 Python 3.5 (2015) 中,通过为
glob模块添加recursive=True参数,正式支持了**模式。 - JavaScript/Node.js: 虽然语言本身没有内置,但 Node.js 生态中的
glob和minimatch等库使其成为前端构建工具(如 Webpack)和配置文件中的标准语法。 - Java: 在 Java 7 (2011) 的 NIO 文件 API 中引入了对
**的支持。 - 构建与配置工具: 像 Apache Ant 这样的构建工具和 Git 的
.gitignore文件很早就开始使用**来匹配多层目录,使其成为开发工作流中不可或缺的一部分。
一个非官方标准的成功
尽管从未被正式标准化,** 凭借其强大的实用性,已经成为一个跨平台、跨语言的共识。它的发展历程清晰地展示了一个源自特定 Shell 的创新如何演变为一个被整个开发社区广泛接受的通用约定。
如果要颁奖的话,我会把创新奖颁给 Zsh,因为它发明了它;营销奖颁给 Ksh,因为它将其命名为“globstar”;而分发奖则颁给 Bash,因为它让每个人的终端都能用上它。