双星号(* *)通配符是什么意思?

我尝试了以下命令,但我不明白结果:

ls **

**是什么意思? 我应该如何使用它?

101551 次浏览

您很可能会看到一些 shell 的特殊特性,它们允许通配符文件名模式跨目录边界进行匹配,这与单个 *相反,后者是仅在目录中匹配的通配符。

如果您没有这样的 shell,那么 **可能等同于 *,因为“匹配零个或多个字符后跟零个或多个字符”与“匹配零个或多个字符”相同。

但是,如果你有这样一个 shell, **将匹配工作目录 和子目录中的所有文件和目录,而 *只匹配工作目录中的文件和目录。(在这两种情况下,名称以 .开头的“点文件”都不匹配)。

**的真正威力来自于你在更具体的模式中使用它。例如,你可以用 **/*.txt指定所有的 .txt文件,不管它们在哪个子目录中,而 *.txt只匹配工作目录中的那些文件。

您应该查看 shell 的通配符匹配规则,以确定 shell 在做什么。例如,bash手册表示:

*
匹配任何字符串,包括空字符串 启用“ globstar”shell 选项,并在文件名中使用“ *” 扩展上下文中,两个相邻的“ *”被用作一个单独的模式 匹配所有文件和零个或多个目录及子目录。 如果后面跟着一个’/’,两个相邻的’* 将只匹配 目录和子目录。

bash的最新版本中,默认情况下“ globstar”shell 选项是禁用的。通过以下方式启用:

shopt -s globstar

我相信 zsh 也支持这种语法。

请记住,通配符是由 shell 展开的,而不是由 ls命令展开的,这一点很重要。如果键入 ls **ls *.txt,则 ls命令本身不会看到 *字符; 它只会看到与模式匹配的扩展文件列表,就像您在命令行中键入了整个列表一样。

这个特定通配符的确切行为已经被其他答案很好地覆盖了,但是关于一般情况的信息可能是有用的。

这种行为不限于 ls,称为“ globbing”,它是基于与现有文件名匹配的模式的扩展。需要注意的是,这些模式并不使用正则表达式语法。

Shell 在将参数发送到程序之前对它们进行预处理。一般来说,膨胀有多个层次,其中一些涉及到球状膨胀。

有关在一个文件通配符模式中可用的其他通配符的更多信息,一个很好的资源是 unix manpage。可以找到 globb 的在线版本 给你

最后,举一个简单的例子,说明这样做可以为您做些什么,特别是当与其他 shell 扩展好处(在本例中是由 bash shell 提供的好处)组合在一起时。关于这个例子中使用的扩展的信息可以在 初学者指南中找到——这是我的 goto 资源,尽管标题是这样的。

ls *{01..04}.{txt,csv}变成 ls *01.txt *01.csv *02.txt *02.csv *03.txt *03.csv *04.txt *04.csv

它可以输出这样的东西:

input_01.txt input_02.txt input_03.txt input_04.txt output_01.csv output_02.csv output_03.csv output_04.csv

跳过以下内容:

input_05.txt input_06.txt input_07.txt input_08.txt input_09.txt input_10.txt output_05.csv output_06.csv output_07.csv output_08.csv output_09.csv output_10.csv

这是一个简单的例子,但是如果您知道这种行为并不是特定于 ls的,那么您可以想象当与 mvcprsync等耦合时的实用程序。

球状

通过使用双星号(**) ,可以使用 一团列出文件系统上的文件。通配符是用于匹配文件路径的字符串或通配符。使用一个或多个 globs 定位文件系统上的文件称为 球状的

除了 Linux shell 之外,globbing 还用于各种配置文件,以指定要查找的文件列表。例如: 在 .gitignore文件中忽略的文件和文件夹,在打字工程中的 tsconfig.json文件中的 filesinclude选项等。

以下是一些最重要的方面的球状和双星号(**)是其中之一:


分段和分离器(/)

分隔符总是 /字符。段是两个分隔符之间的所有内容。

例子: Tests/HelloWorld.js

在这里,TestsHelloWorld.js是片段,/是分离器。


单星号(*)

单星号(*)匹配 段中的零个或多个字符。它用于对一个目录中的文件进行全球化。

例子: *.js

这个 Globb 将匹配诸如 HelloWorld.js之类的文件,但不匹配诸如 Tests/HelloWorld.jsTests/UI/HelloWorld.js之类的文件


双星号(**)

双星号(**)匹配整个 多个段中的零个或多个字符。它用于对嵌套目录中的文件进行 globbing。

例子: Tests/**/*.js

在这里,文件选择将仅限于 Tests目录。这个通配符将匹配诸如 Tests/HelloWorld.jsTests/UI/HelloWorld.jsTests/UI/Feature1/HelloWorld.js之类的文件。


问号(?)

问号(?)匹配一个段中的单个字符。当某些文件或目录的名称只有一个字符不同时,可以使用 ?

例子: tests/?at.js

这将匹配文件,如 tests/cat.jstest/Cat.jstest/bat.js等。


方括号([abc])

方括号([...])用方括号中提到的单个字符填充文件。

例子: tests/[CB]at.js

这个地球仪将匹配文件,如 tests/Cat.jstests/Bat.js


方括号范围([a-z])

方括号范围([a-z]) ,匹配范围中指定的一个字符。

例子: tests/feature[1-9]/HelloWorld.js

这个地球仪将匹配文件,如 tests/feature1/HelloWorld.jstest/feature2/HelloWorld.js等等... 到 9


否定(!)

否定(!)可用于排除某些文件。

例子1: tests/[!C]at.js

这将排除文件 tests/Cat.js,并将匹配文件,如 tests/Bat.jstests/bat.jstests/cat.js

在数组内的配置文件中也使用否定来否定或排除某些文件。

例子2: ['Tests/**/*.js', '!Tests/UI/**']

这将排除 Tests/UI目录中的所有文件和文件夹。


就是这样,希望能有帮助!

为视觉化的人准备的

其他的答案是 很难做到这一点为视觉的人喜欢我。这里是一个插图 经测试完全确认。它显示了在阅读文本定义时不明显的 **的细微差别。

下面所示的目录结构具有以下属性:

  • 四个目录级别(计算根目录)
  • 每个级别有两个文件 f和不同的文件扩展名
  • 在不同深度的不同分支上有两个名称相同的目录 o

我对照这个结构测试了下面表格标题中的所有模式, 在启用 globstar 的 Bash 中使用以下命令: stat -f "%N" <pattern>

.
├── f.js
├── f.md
└── x
├── f.js
├── f.md
├── o
│   ├── f.js
│   ├── f.md
│   └── z
│       ├── f.js
│       └── f.md
└── y
├── f.js
├── f.md
└── o
├── f.js
└── f.md

比较 ***

* ** */ **/ */*.md **/*.md */o/* **/o/* **/o/**
f.js Something Something
f.md Something Something Something
x Something Something Something Something
x/f.js Something
x/f.md Something Something Something
x/o Something Something Something
x/o/f.js Something Something Something Something
x/o/f.md Something Something Something Something Something
x/o/z Something Something Something Something Something
x/o/z/f.js Something Something
x/o/z/f.md Something Something Something
x/y Something Something
x/y/f.js Something
x/y/f.md Something Something
x/y/o Something Something Something
x/y/o/f.js Something Something Something
x/y/o/f.md Something Something Something Something

选择性深度瞄准

在这里,我们有选择地瞄准目录树中不同部分的 Markdown 文件:

只有 < br/> 当前目录 任何地方 x/o下的任何地方 < br/> 任何 o下的任何地方 < br/> 仅在任意 o下直接 < br/>
*.md **/*.md x/o/**/*.md **/o/**/*.md **/o/*.md
f.js
f.md Something Something
x
x/f.js
x/f.md Something
x/o
x/o/f.js
x/o/f.md Something Something Something Something
x/o/z
x/o/z/f.js
x/o/z/f.md Something Something Something
x/y
x/y/f.js
x/y/f.md Something
x/y/o
x/y/o/f.js
x/y/o/f.md Something Something Something

**.md*.md相同

**.md的工作原理与 *.md相似,而与 **/*.md不同。如果你给 **附加或者预先设置了 /以外的东西,它的工作原理和 *完全一样。