Pau*_*ce. 104
这将在Bash 4中起作用:
ls -l {,**/}*.ext
Run Code Online (Sandbox Code Playgroud)
为了使双星号glob工作,globstar需要设置该选项(默认值:on):
shopt -s globstar
Run Code Online (Sandbox Code Playgroud)
来自man bash:
globstar
If set, the pattern ** used in a filename expansion con?
text will match a files and zero or more directories and
subdirectories. If the pattern is followed by a /, only
directories and subdirectories match.
现在我想知道是否曾经有过globstar处理中的错误,因为现在只使用ls **/*.ext我得到了正确的结果.
无论如何,我看着分析使用VLC库kenorb确实发现了一些问题与分析,并在正上方我的回答:
与find命令输出的比较无效,因为指定-type f不包括其他文件类型(特别是目录),并且ls列出的命令可能包含.此外,列出的命令之一ls -1 {,**/}*.*- 似乎基于我的上面,只输出包含子目录中的那些文件的点的名称.OP的问题和我的答案包括一个点,因为正在寻找的是具有特定扩展名的文件.
然而,最重要的是,使用ls带有globstar模式的命令存在一个特殊问题**.由于模式被Bash扩展到正在检查的树中的所有文件名(和目录名),因此出现了许多重复项.在扩展之后,如果它们是目录,则ls命令列出它们中的每一个及其内容.
例:
在我们当前的目录中是子目录A及其内容:
A
??? AB
??? ABC
??? ABC1
??? ABC2
??? ABCD
??? ABCD1
Run Code Online (Sandbox Code Playgroud)
在该树中,**扩展为"AA/AB A/AB/ABC A/AB/ABC/ABC1 A/AB/ABC/ABC2 A/AB/ABC/ABCD A/AB/ABC/ABCD/ABCD1"(7个条目) .如果你这样做echo **,你得到的确切输出,每个条目代表一次.但是,如果你这样做,ls **它将输出每个条目的列表.所以基本上它ls A跟着ls A/AB等等,所以A/AB显示两次.此外,ls将分别设置每个子目录的输出:
...
<blank line>
directory name:
content-item
content-item
Run Code Online (Sandbox Code Playgroud)
因此,使用wc -l计算所有那些空白行和目录名称部分标题,这会使计数更进一步.
这是你不应该解析的ls另一个原因.
作为进一步分析的结果,我建议不要在任何情况下使用globstar模式,除了以这种方式迭代文件树:
for entry in **
do
something "$entry"
done
Run Code Online (Sandbox Code Playgroud)
作为最后的比较,我使用了一个方便的Bash源代码库并执行了此操作:
shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .
Run Code Online (Sandbox Code Playgroud)
我曾经tr将空格更改为换行符,这在此只有效,因为没有名称包含空格.我曾经从每行输出中sed删除前导.我对输出进行了排序,因为它通常是未排序的,并且Bash的globs扩展已经排序.如您所见,唯一的输出是当前目录输出.当我这样做时,输出几乎是两倍的线../findfinddiff.findls ** | wc -l
unu*_*tbu 13
这将打印当前目录及其子目录中以".ext"结尾的所有文件.
find . -name '*.ext' -print
Run Code Online (Sandbox Code Playgroud)
您可以使用:**/*.*以递归方式包含所有文件(通过以下方式启用:) shopt -s globstar.
请在下面找到其他变体的测试以及它们的行为方式.
在示例VLC存储库文件夹中测试包含3472个文件的文件夹:
(3472文件总数计为每:find . -type f | wc -l)
ls -1 **/*.* - 返回3338ls -1 {,**/}*.*- 返回3341(由Dennis提出)ls -1 {,**/}* - 返回8265ls -1 **/*- 返回7817,隐藏文件除外(由Dennis提议)ls -1 **/{.[^.],}*- 返回7869(由丹尼斯提议)ls -1 {,**/}.?* - 返回15855ls -1 {,**/}.* - 返回20321因此,我认为递归列出所有文件的最接近的方法是第一个示例(**/*.*)根据gniourf-gniourf注释(假设文件具有适当的扩展名,或使用特定的扩展名),因为第二个示例提供了更多重复项,如下所示:
$ diff -u <(ls -1 {,**/}*.*) <(ls -1 **/*.*)
--- /dev/fd/63 2015-04-19 15:25:07.000000000 +0100
+++ /dev/fd/62 2015-04-19 15:25:07.000000000 +0100
@@ -1,6 +1,4 @@
COPYING.LIB
-COPYING.LIB
-Makefile.am
Makefile.am
@@ -45,7 +43,6 @@
compat/tdestroy.c
compat/vasprintf.c
configure.ac
-configure.ac
Run Code Online (Sandbox Code Playgroud)
而另一个产生更多的重复.
要包含隐藏文件,请使用:( shopt -s dotglob禁用shopt -u dotglob).不建议这样做,因为它会影响mv或rm等命令,并且您可能会意外删除错误的文件.
小智 6
为什么不使用大括号扩展来包含当前目录呢?
./{*,**/*}.ext
Run Code Online (Sandbox Code Playgroud)
大括号扩展发生在 glob 扩展之前,因此您可以有效地使用旧版本的 bash 执行您想要的操作,并且可以放弃在较新版本中使用 globstar 的猴子。
此外,在 bash 中包含领先./的 glob 模式被认为是一种很好的做法。