我的目标是列出所有与foo/**
匹配的文件,而此文件夹包含文件(1和2)和子目录(bar),其中包含文件:
foo/
├── 1
└── bar
└── 2
Bash有一个内置的compgen
。我在这个答案中发现了这个函数。使用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)。
- Bash version 5.0.17(1)-release (x86_64-pc-linux-gnu) on Ubuntu 20.04.
- Bash globstar选项打开/关闭不会改变任何东西 Python 3.6.9
compgen
是一个专门用于生成补全的工具。它确实看起来有bug(因为它不支持globstar
选项),但它也不是用来生成匹配glob的文件列表的最佳工具;因此,没有真正的实际理由让这个bug成为任何人关心的问题。
最好的工具是glob表达式。
shopt -s extglob nullglob
files=( foo/** ) # store files matching foo/** in an array
echo "Found ${#files[@]} files:"
printf ' - %qn' "${files[@]}"
如果在您的实际环境中,您希望获得从变量展开的glob表达式,并且只有执行globb并抑制字符串分割,那么您需要在执行files=( $glob )
赋值时临时将IFS
设置为空值。