双星号 (**) 通配符是啥意思?
Posted
技术标签:
【中文标题】双星号 (**) 通配符是啥意思?【英文标题】:What do double-asterisk (**) wildcards mean?双星号 (**) 通配符是什么意思? 【发布时间】:2015-03-26 10:16:57 【问题描述】:我尝试了以下命令,但无法解释结果:
ls **
我不确定它到底输出了什么以及为什么。
【问题讨论】:
【参考方案1】:您很可能会看到一些 shell 的特殊功能,它允许通配符文件名模式跨目录边界匹配,而不是单个 *
,后者是仅在目录内匹配的通配符。
如果您没有这样的 shell,**
可能会等同于 *
,因为“匹配零个或多个字符后跟零个或多个字符”与仅“匹配零个或多个字符”相同.
但如果你有这样的 shell,**
将匹配当前目录中的所有文件和目录和子目录,而*
只匹配当前目录中的文件和目录。 (在这两种情况下,名称以.
开头的“点文件”都不匹配)。
**
的真正威力来自于您在更具体的模式中使用它。例如,**/*.txt
可以指定所有.txt
文件,无论它们位于哪个子目录中,而*.txt
仅匹配当前目录中的文件。
您应该查看您的 shell 的通配符匹配规则,以确定您的 shell 正在做什么。例如,bash
manual 表示:
*
匹配任何字符串,包括空字符串。当。。。的时候 'globstar' shell 选项已启用,并且在文件名中使用了 '*' 扩展上下文,两个相邻的 '*' 用作单个模式将 匹配所有文件和零个或多个目录和子目录。 如果后跟一个 '/',两个相邻的 '*' 将只匹配 目录和子目录。
在bash
的最新版本中,'globstar' shell 选项默认被禁用。通过以下方式启用:
shopt -s globstar
我相信 zsh 也支持这种语法。
请务必记住,通配符是由 shell 扩展的,而不是由 ls
命令扩展的。如果您键入ls **
或ls *.txt
,ls
命令本身永远不会看到*
字符;它只会看到与模式匹配的扩展文件列表,就像您在命令行上键入了整个列表一样。
【讨论】:
它比“匹配当前目录和子目录中的所有文件和目录”或 bash 手册中所说的稍有细微差别,但只有一点点。请参阅***.com/a/66744400/8910547底部的表格和我对`**.md`和**f.md
的评论
我编辑了解释,理顺了流程,添加了一个例子,并取消了对“递归”的引用,这意味着不同的东西......(正如 Inigo Montoya 所说,“你一直在使用那个词. 我不认为这意味着你认为它意味着什么。”?)【参考方案2】:
其他答案已很好地涵盖了此特定通配符的确切行为,但有关一般情况的信息可能有用。
这种行为不限于ls
,被称为“globbing”,它是基于与现有文件名匹配的模式扩展。需要注意的是,这些模式不使用正则表达式语法。
shell 在将参数发送到程序之前对其进行预处理。通常有多个级别的扩展,其中一些涉及通配。
有关文件 glob 模式中可用的其他通配符的更多信息的一个很好的资源是 unix 联机帮助页。可以找到 glob 的在线版本here。
最后,这是一个简单的例子,说明它可以为您做什么,尤其是与其他 shell 扩展好东西结合使用时,在这种情况下是由 bash
shell 提供的。有关此示例中使用的扩展的信息可以在 Bash Guide for Beginners 中找到 - 这是我的 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
,那么您可以想象与 mv
、cp
、rsync
等结合使用时的实用程序。
【讨论】:
【参考方案3】:通配符
通过使用双星号 (**
),您正在使用 glob 列出文件系统上的文件。 glob 是用于匹配文件路径的文字或通配符字符串。使用一个或多个 glob 在文件系统上定位文件称为 globbing。
除了 Linux shell,globbing 还用于各种配置文件中,以指定要定位的文件列表。例如:.gitignore
文件中要忽略的文件和文件夹,Typescript 项目中tsconfig.json
文件中的files
和include
选项等。
以下是通配符的一些最重要的方面,双星号 (**
) 就是其中之一:
段和分隔符 (/
)
分隔符始终是/
字符。段是介于两个分隔符之间的所有内容。
示例:Tests/HelloWorld.js
这里,Tests
和 HelloWorld.js
是分段,/
是分隔符。
单个星号 (*
)
单个星号 (*
) 匹配 一个 段中的零个或多个字符。它用于对一个目录中的文件进行通配。
示例:*.js
此 glob 将匹配 HelloWorld.js
等文件,但不匹配 Tests/HelloWorld.js
或 Tests/UI/HelloWorld.js
等文件
双星号 (**
)
双星号 (**
) 匹配 多个 段中的零个或多个字符。它用于对嵌套目录中的文件进行通配。
示例:Tests/**/*.js
在这里,文件选择将被限制在Tests
目录中。 glob 将匹配 Tests/HelloWorld.js
、Tests/UI/HelloWorld.js
、Tests/UI/Feature1/HelloWorld.js
等文件。
问号(?
)
问号(?
) 匹配一个段中的单个字符。当某些文件或目录的名称仅相差一个字符时,您可以使用?
。
示例:tests/?at.js
这将匹配tests/cat.js
、test/Cat.js
、test/bat.js
等文件。
方括号 ([abc]
)
方括号 ([...]
) 使用方括号中提到的单个字符对文件进行全局化。
示例:tests/[CB]at.js
此 glob 将匹配 tests/Cat.js
或 tests/Bat.js
等文件
方括号范围 ([a-z]
)
方括号范围 ([a-z]
),匹配范围中指定的一个字符。
示例:tests/feature[1-9]/HelloWorld.js
此 glob 将匹配 tests/feature1/HelloWorld.js
、test/feature2/HelloWorld.js
等文件...直到 9
。
否定 (!
)
否定 (!) 可用于排除某些文件。
示例 1:tests/[!C]at.js
这将排除文件tests/Cat.js
,并将匹配tests/Bat.js
、tests/bat.js
、tests/cat.js
等文件。
Negation 也用于数组内的配置文件中,以否定或排除某些文件。
示例 2:['Tests/**/*.js', '!Tests/UI/**']
这将排除 Tests/UI
目录中的所有文件和文件夹。
就是这样!希望对您有所帮助!
【讨论】:
注意:globstar
shell 选项在最近的 bash 版本中默认禁用,因此**
(双星号)与Tests/HelloWorld.js
不匹配。要启用它,请使用 shopt -s globstar
和 shopt -u globstar
禁用。【参考方案4】:
虽然其他一个或多个答案可能是正确的,但它们有点难以理解,尤其是如果您是像我这样的视觉型人。
所以我决定提供一个直观的答案,通过测试完全确认。
我创建了以下目录结构,每个级别都有两个文件“f”,一个有文件扩展名,一个没有文件扩展名,然后在 Darwin 上的 Bash 中使用以下命令测试下表标题中的所有模式启用 globstar:stat -f "%N" <pattern>
。
如果你是一个视觉型的人,看表格会让你更深入地理解**
的含义,而不是仅仅阅读其他书籍中的定义答案。
.
├── f
├── f.md
└── x
├── f
├── f.md
└── y
├── f
├── f.md
└── z
├── f
└── f.md
比较 *
和 **
* |
** |
*/ |
**/ |
**/*.* |
x/*.* or*/*.*
|
x/* or*/*
|
x/** or*/**
|
|
---|---|---|---|---|---|---|---|---|
f |
✅ | ✅ | ||||||
f.md |
✅ | ✅ | ✅ | |||||
x |
✅ | ✅ | ✅ | ✅ | ✅ | |||
x/f |
✅ | ✅ | ✅ | |||||
x/f.md |
✅ | ✅ | ✅ | ✅ | ✅ | |||
x/y |
✅ | ✅ | ✅ | ✅ | ||||
x/y/f |
✅ | ✅ | ||||||
x/y/f.md |
✅ | ✅ | ✅ | |||||
x/y/z |
✅ | ✅ | ✅ | |||||
x/y/z/f |
✅ | ✅ | ||||||
x/y/z/f.md |
✅ | ✅ | ✅ |
在树中匹配或查找文件
*.md **.md **f.md f**.md
|
*/*.md x/*.md **/x/*.md
|
*/*/*.md x/*/*.md **/y/*.md
|
*/*/*/*.md x/*/*/*.md **/z/*.md
|
x/**/*.md
|
**/*.md
|
|
---|---|---|---|---|---|---|
f |
||||||
f.md |
✅ | ✅ | ||||
x |
||||||
x/f |
||||||
x/f.md |
✅ | ✅ | ✅ | |||
x/y |
||||||
x/y/f |
||||||
x/y/f.md |
✅ | ✅ | ✅ | |||
x/y/z |
||||||
x/y/z/f |
||||||
x/y/z/f.md |
✅ | ✅ | ✅ |
请注意,在 **
之前或附加 /
以外的任何内容时,它的作用与 *
相同,如上所示 **.md
和 **f.md
,两者都不匹配 x/y/f.md
例子。
【讨论】:
如果文件夹名称中有星号呢? @pablete:*
还涵盖名称中带有星号的文件。如果你想选择这样的文件,你可以使用ls *'*'*
(只需在星号周围加上引号)以上是关于双星号 (**) 通配符是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章