Bash compgen 没有正确解析通配符

Bash compgen not parsing wildcard correctly

我的目标是列出与 foo/** 匹配的所有文件,而此文件夹包含文件(1 和 2)和子目录 (bar),文件为:

foo/
├── 1
└── bar
    └── 2

Bash 有一个名为 compgen 的内置函数。我发现了这个函数 in this answer。使用 compgen -G <pattern>,在我的例子中 compgen -G 'foo/**' 应该列出所有文件和文件夹。但是,它只打印出第一个文件夹 (foo) 的内容:

foo/bar
foo/1

-> foo/bar/2 不见了!我希望得到以下输出:

foo/bar
foo/1
foo/bar/2

这是 bash 的 compgen 中的错误还是 glob 不正确?


更多实验

$ compgen -G 'foo/**/*'
foo/bar/2

使用 Python3 的 pathlib.Path.glob:

from pathlib import Path
p=Path(".").resolve()
[print(f) for f in p.glob("foo/**")]

输出:

foo
foo/bar

from pathlib import Path
p=Path(".").resolve()
[print(f) for f in p.glob("foo/**/*")]

输出:

foo/1
foo/bar
foo/bar/2

这个版本完全符合我的要求,但是,我更愿意尽量减少依赖性并且根本不使用 Python(仅 bash)。


compgen是一个专门用于生成补全的工具。它 似乎有问题(因为它不支持 globstar 选项),但它也不是用于生成匹配文件列表的最佳工具全球;所以没有真正实际的理由让这个错误成为任何人关心的错误。

最好的工具就是 glob 表达式。

shopt -s extglob nullglob
files=( foo/** ) # store files matching foo/** in an array
echo "Found ${#files[@]} files:"
printf ' - %q\n' "${files[@]}"

如果在您的 real-world 环境中您想要从变量扩展 glob 表达式,并且 执行 globbing 并抑制 string-splitting,那么您希望在执行 files=( $glob ) 赋值时临时将 IFS 设置为空值。