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

Ram*_*mon 87 bash shell glob wildcard shopt

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

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

  • 最好的答案!但我认为`**/*.ext`应该足够了.此外,除非你"shopt -s dotglob",否则你不会拥有隐藏文件. (12认同)
  • 我测试了Ubuntu和Cygwin,并且`globstar`被默认为'off` (5认同)
  • @gniourf_gniourf这个问题实际上要求特别包含当前目录,否则`**/*.ext`将不够 (4认同)
  • 要禁用`globstar`:`shopt -u globstar`. (2认同)
  • macOS 附带的 bash 版本似乎也有缺陷。`{*,**/*}` 仅匹配当前目录及其子目录,但不匹配这些子目录的子目录。并且`shopt`列表没有`globstar`。我已经尝试过使用 homebrew (4.4.23(1)) 附带的 bash shell 和 globstar,它对我的​​ glob 模式执行相同的操作。 (2认同)
  • @dotnetCarpenter:MacOS附带的Bash版本是3.2,它不支持globstar,正如你所发现的那样.双星号的处理方式与单个星号相同.Globstar在Bash 4.0中推出. (2认同)

unu*_*tbu 13

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

find . -name '*.ext' -print
Run Code Online (Sandbox Code Playgroud)


ken*_*orb 6

您可以使用:**/*.*以递归方式包含所有文件(通过以下方式启用:) shopt -s globstar.

请在下面找到其他变体的测试以及它们的行为方式.


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

(3472文件总数计为每:find . -type f | wc -l)

  • ls -1 **/*.* - 返回3338
  • ls -1 {,**/}*.*- 返回3341(由Dennis提出)
  • ls -1 {,**/}* - 返回8265
  • ls -1 **/*- 返回7817,隐藏文件除外(由Dennis提议)
  • ls -1 **/{.[^.],}*- 返回7869(由丹尼斯提议)
  • ls -1 {,**/}.?* - 返回15855
  • ls -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).不建议这样做,因为它会影响mvrm等命令,并且您可能会意外删除错误的文件.


小智 6

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

./{*,**/*}.ext
Run Code Online (Sandbox Code Playgroud)

大括号扩展发生在 glob 扩展之前,因此您可以有效地使用旧版本的 bash 执行您想要的操作,并且可以放弃在较新版本中使用 globstar 的猴子。

此外,在 bash 中包含领先./的 glob 模式被认为是一种很好的做法。