什么扩展到当前目录中的所有文件递归?

时间:2009-11-06 22:07:00

标签: bash shell wildcard glob

我知道**/*.ext扩展到与*.ext匹配的所有子目录中的所有文件,但是什么是类似的扩展,包括当前目录中的所有此类文件?< / p>

5 个答案:

答案 0 :(得分:99)

这将适用于Bash 4:

ls -l {,**/}*.ext

为了使双星号glob工作,需要设置globstar选项(默认值:on):

shopt -s globstar

来自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存储库的analysis kenorb,并发现了该分析的一些问题以及我上面的答案:

find命令输出的比较无效,因为指定-type f不包括其他文件类型(特别是目录),并且列出的ls命令可能会这样做。此外,列出的其中一个命令ls -1 {,**/}*.* - 似乎基于我的上面的命令,只输出包含点的名称​​,用于子目录中的那些文件。 OP的问题和我的答案包括一个点,因为正在寻找的是具有特定扩展名的文件。

然而,最重要的是,使用带有globstar模式ls的{​​{1}}命令存在一个特殊问题。由于模式被Bash扩展到正在检查的树中的所有文件名(和目录名),因此出现了许多重复项。扩展后,**命令会列出 每个 及其内容(如果它们是目录)。

示例:

在我们当前的目录中是子目录ls及其内容:

A

在该树中,A └── AB    └── ABC    ├── ABC1    ├── ABC2    └── ABCD       └── ABCD1 扩展为“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 计算所有空白行和目录名称部分标题,这些标题会使计数更加突出。

这是你不应该parse ls的另一个原因。

作为进一步分析的结果,我建议不要在任何情况下使用globstar模式,而不是以这种方式迭代文件树:

wc -l

作为最后的比较,我使用了一个方便的Bash源代码库,并且做了这个:

for entry in **
do
    something "$entry"
done

我使用shopt -s globstar dotglob diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort) 0a1 > . 将空格更改为换行符,这仅在此处有效,因为没有名称包含空格。我使用trsed的每一行输出中删除了前导./。我对find的输出进行了排序,因为它通常是未排序的,并且Bash的globs扩展已经排序。如您所见,find的唯一输出是diff输出的当前目录.。当我做find时,输出的行几乎是两倍。

答案 1 :(得分:12)

这将打印当前目录及其子目录中以“.ext”结尾的所有文件。

find . -name '*.ext' -print

答案 2 :(得分:6)

您可以使用:**/*.*递归包含所有文件(由shopt -s globstar启用)。

请在下面查看其他变体的测试以及它们的行为方式。


在示例VLC存储库文件夹中测试包含3472个文件的文件夹:

(根据find . -type f | wc -l计算的总文件数为3472)

  • ls -1 **/*.* - 返回3338
  • ls -1 {,**/}*.* - 返回3341(由Dennis提议)
  • ls -1 {,**/}* - 返回8265
  • ls -1 **/* - 返回7817,隐藏文件除外(由Dennis提议)
  • ls -1 **/{.[^.],}* - 返回7869(由Dennis提议)
  • ls -1 {,**/}.?* - 返回15855
  • ls -1 {,**/}.* - 返回20321

所以我认为递归列出所有文件的最接近的方法是gniourf-gniourf comment的第一个示例(**/*.*)(假设文件具有适当的扩展名,或使用特定的扩展名),如第二个例子提供了更多重复项,如下所示:

$ 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

,另一个产生更多重复。


要包含隐藏文件,请使用:shopt -s dotglob(由shopt -u dotglob禁用)。不建议这样做,因为它会影响mvrm等命令,您可能会意外删除错误的文件。

答案 3 :(得分:3)

$ find . -type f

这将列出当前目录中的所有文件。然后,您可以使用-exec

对输出执行其他命令
$find . -type f -exec grep "foo" {} \;

这将从查找字符串“foo”grep每个文件。

答案 4 :(得分:3)

为什么不使用大括号扩展来包含当前目录呢?

./{*,**/*}.ext

Brace扩展在全局扩展之前发生,因此您可以使用旧版本的bash有效地执行您想要的操作,并且可以在较新版本中放弃使用globstar进行修改。

此外,bash中的优秀做法是在您的glob模式中包含前导./