Bash:使用文件名中的空格展开大括号和全局?

Jay*_*ker 10 bash filenames glob

我有一些文件看起来像:

/path/with spaces/{a,b,c}/*.gz
Run Code Online (Sandbox Code Playgroud)

我需要在a,b,cdirs 子集下匹配glob的所有文件最终作为单个命令的参数:

mycmd '/path/with spaces/a/1.gz' '/path/with spaces/a/2.gz' '/path/with spaces/c/3.gz' ...
Run Code Online (Sandbox Code Playgroud)

我关心的目录作为命令行参数进入,我将它们放在一个数组中:

dirs=( "$@" )
Run Code Online (Sandbox Code Playgroud)

我想做的事情如下:

IFS=,
mycmd "/path/with spaces/{${dirs[*]}}/"*.gz
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为bash在变量之前扩展括号.我曾尝试过使用echols甚至eval(*shudder*)的技巧,但很难让它们与文件名中的空格一起使用. find似乎没有多大帮助,因为它没有做括号.我可以为数组中的每个目录获取一个单独的glob:

dirs=( "${dirs[@]/#//path/with spaces/}" )
dirs=( "${dirs[@]/%//*.gz}" )
Run Code Online (Sandbox Code Playgroud)

但随后bash在扩展时引用了通配符.

那么:是否有一种优雅的方法可以使所有文件与变量括号和glob模式匹配,正确处理空间,还是我坚持做循环?如果这有所作为,我正在使用Bash 3.

Sha*_*hin 7

要在带空格的路径上执行大括号扩展和通配,您可以引用包含空格的路径部分,例如

mycmd '/path/with spaces/'{a,b,c}/*.gz
Run Code Online (Sandbox Code Playgroud)

使用变量中的值列表进行大括号扩展有点棘手,因为大括号扩展是在任何其他扩展之前完成的.我没有看到任何办法,只能使用可怕的eval.

eval mycmd "'/path/with spaces/'{a,b,c}/*.gz"
Run Code Online (Sandbox Code Playgroud)

PS在这种情况下,我个人会选择一个循环来构建参数列表而不是上面显示的方法.虽然更详细,但是对于没有经验的人而言,循环将更容易阅读并且将避免使用eval(特别是当扩展候选者来自用户输入时!).


概念证明:

使用伪命令(x.sh)打印出参数的数量并打印出每个参数:

[me@home]$ shopt -s nullglob  # handle case where globbing returns no match

[me@home]$ ./x.sh 'path with space'/{a,b}/*.txt
Number of arguments = 3
- path with space/a/1.txt
- path with space/b/2.txt
- path with space/b/3.txt

[me@home]:~/temp$ dirs="a,b"
[me@home]k:~/temp$ eval ./x.sh "'path with space'/{$dirs}/*.txt"
Number of arguments = 3
- path with space/a/1.txt
- path with space/b/2.txt
- path with space/b/3.txt


Jay*_*ker 5

好的,这里是使用 bash 作为“大括号”和find通配符的一个:

find "${dirs[@]/#//path/with spaces/}" -name '*.gz' -print0 | xargs -0 mycmd
Run Code Online (Sandbox Code Playgroud)

如果您需要数组中的结果,很有用。