ls **
**
是什么意思?我应该如何使用它?
ls **
**
是什么意思?我应该如何使用它?
您很可能看到的是一些shell特殊功能,允许通配符文件名模式跨越目录边界匹配,而不是单个*
,它只能在目录内匹配。
如果您没有这样的shell,则**
可能等同于*
,因为“匹配零个或多个字符后跟零个或多个字符”与“仅匹配零个或多个字符”相同。
但如果您有这样的shell,**
将匹配当前目录和子目录中的所有文件和目录,而*
仅匹配当前目录中的文件和目录。 (在两种情况下,“点文件”,即名称以.
开头的文件,不会被匹配)。
**
的真正威力在于您在更具体的模式中使用它。例如,您可以使用**/*.txt
指定所有.txt
文件,无论它们位于哪个子目录中,而*.txt
仅匹配当前目录中的文件。
您应该查看您的shell的通配符匹配规则,以确切了解您的shell正在执行的操作。例如,bash
手册中写道:
*
匹配任何字符串,包括空字符串。当启用“globstar”shell选项并在文件名扩展上下文中使用“*”时,将两个相邻的“*”用作单个模式将匹配所有文件和零个或多个目录和子目录。如果后面跟着“/”,则两个相邻的“*”仅匹配目录和子目录。
在最近版本的bash
中,默认情况下禁用“globstar”shell选项。可以通过以下方式启用:
shopt -s globstar
我相信zsh也支持这种语法。
需要记住的是通配符是由shell而不是ls
命令来扩展的。如果您输入ls **
或ls *.txt
,那么ls
命令本身永远不会看到*
字符;它只会看到与模式匹配的已扩展文件列表,就好像您在命令行上键入了整个列表一样。
双星号 (**
) 是使用通配符在文件系统上列出文件的方式。通配符是一组用于匹配文件路径的字面值或通配符字符。在文件系统上使用一个或多个通配符来定位文件,称为通配符匹配。
除了Linux shell之外,通配符匹配还用于各种配置文件中,以指定要定位的文件列表。例如:在 .gitignore
文件中忽略的文件和文件夹,在 Typescript 项目中的 tsconfig.json
文件中的 files
和 include
选项等。
以下是通配符匹配的一些最重要的方面,其中双星号 (**
) 是其中之一:
/
)分隔符始终是/
字符。段是两个分隔符之间的所有内容。
例: Tests/HelloWorld.js
在此示例中,Tests
和 HelloWorld.js
是段,/
是分隔符。
*
)单个星号 (*
) 匹配一个段内的零个或多个字符,用于匹配一个目录中的文件。
例: *.js
**
)双星号 (**
) 匹配多个路径组成的零个或多个字符。它用于匹配嵌套目录中的文件。
例如:Tests/**/*.js
在这里,所选文件将被限制在 Tests
目录下。该通配符将匹配文件如 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
这个通配符将匹配文件如 tests/Cat.js
或 tests/Bat.js
。
[a-z]
)方括号范围([a-z]
)匹配方括号中列出的字符范围内的任何单个字符的文件。
方括号范围 ([a-z]
),匹配指定范围内的一个字符。
例子:tests/feature[1-9]/HelloWorld.js
这个通配符可以匹配像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
这样的文件。
否定也可以在配置文件中的数组内用于否定或排除一些文件。
例子 2: ['Tests/**/*.js', '!Tests/UI/**']
这将从Tests/UI
目录中排除所有文件和文件夹。
globstar
Shell选项,因此**
(双星号)不会匹配Tests/HelloWorld.js
。要启用它,请使用shopt -s globstar
,并使用shopt -u globstar
来禁用它。 - Max_Payne{ }
呢?我认为它们也可以与 globbing 一起使用。 - AdmiralAdama{...}
是扩展语法,而不是通配符操作符。扩展发生在通配符之前。例如,*.{js,ts,java}
将会被扩展为*.js *.ts *.java
。 - Yogesh Umesh Vaity对于像我这样的视觉型人群来说,其他答案很难理解。这里有一张图示已通过测试完全确认。它展示了在读取文本定义时不明显的**
细微差别。
下面显示的目录结构具有以下属性:
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 |
✅ | ✅ | |||||||
f.md |
✅ | ✅ | ✅ | ||||||
x |
✅ | ✅ | ✅ | ✅ | |||||
x/f.js |
✅ | ||||||||
x/f.md |
✅ | ✅ | ✅ | ||||||
x/o |
✅ | ✅ | ✅ | ||||||
x/o/f.js |
✅ | ✅ | ✅ | ✅ | |||||
x/o/f.md |
✅ | ✅ | ✅ | ✅ | ✅ | ||||
x/o/z |
✅ | ✅ | ✅ | ✅ | ✅ | ||||
x/o/z/f.js |
✅ | ✅ | |||||||
x/o/z/f.md |
✅ | ✅ | ✅ | ||||||
x/y |
✅ | ✅ | |||||||
x/y/f.js |
✅ | ||||||||
x/y/f.md |
✅ | ✅ | |||||||
x/y/o |
✅ | ✅ | ✅ | ||||||
x/y/o/f.js |
✅ | ✅ | ✅ | ||||||
x/y/o/f.md |
✅ | ✅ | ✅ | ✅ |
在这里,我们有选择性地定位目录树中不同部分的Markdown文件:
仅当前目录 | 任何位置 | 在x/o 下的任何位置 |
在任何o 下的任何位置 |
仅直接在任何o 下 |
|
---|---|---|---|---|---|
*.md |
**/*.md |
x/o/**/*.md |
**/o/**/*.md |
**/o/*.md |
|
f.js |
|||||
f.md |
✅ | ✅ | |||
x |
|||||
x/f.js |
|||||
x/f.md |
✅ | ||||
x/o |
|||||
x/o/f.js |
|||||
x/o/f.md |
✅ | ✅ | ✅ | ✅ | |
x/o/z |
|||||
x/o/z/f.js |
|||||
x/o/z/f.md |
✅ | ✅ | ✅ | ||
x/y |
|||||
x/y/f.js |
|||||
x/y/f.md |
✅ | ||||
x/y/o |
|||||
x/y/o/f.js |
|||||
x/y/o/f.md |
✅ | ✅ | ✅ |
**.md
与*.md
相同**.md
的作用类似于*.md
,而不是**/*.md
。 如果在**
之前或之后添加除/
以外的任何内容,则其将与*
完全相同。
\*
转义@MaximSuslov
。 - masonCherrypath.is_file()
来过滤掉目录。根据图表,我希望使用"*/*"或者"*/*.*"可以实现,但实际上并不行。 - undefined其他答案已经很详细地介绍了这个通配符的确切行为,但一般情况下的信息可能也会有用。
这种行为不仅限于ls
命令,并称为“globbing”,即根据与现有文件名的匹配来扩展模式。需要注意的是,这些模式不使用正则表达式语法。
在将参数发送到程序之前,Shell会对其进行预处理。通常有多个级别的扩展,其中一些涉及globbing。
有关文件glob模式中其他通配符的更多信息的绝佳资源是unix manpage。可以在这里找到glob在线版本。
最后,这里有一个简单的示例可以为您做什么,特别是当与其他shell扩展好处结合使用时,在本例中是由bash
shell提供的扩展。有关在此示例中使用的扩展的信息可以在Bash Guide for Beginners中找到——尽管标题是入门指南,但这是我的首选资源。
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
等命令配合使用时就可以想象其有多实用。