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

时间:2013-01-17 14:51:36

标签: bash filenames glob

我有一些看起来像的文件:

/path/with spaces/{a,b,c}/*.gz

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

mycmd '/path/with spaces/a/1.gz' '/path/with spaces/a/2.gz' '/path/with spaces/c/3.gz' ...

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

dirs=( "$@" )

我想做类似的事情:

IFS=,
mycmd "/path/with spaces/{${dirs[*]}}/"*.gz

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

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

然后bash在扩展时引用通配符。

所以:有没有一种优雅的方法可以让所有文件与变量括号和glob模式匹配,正确处理空格,还是我坚持做循环?我正在使用Bash 3,如果这有所不同。

3 个答案:

答案 0 :(得分:7)

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

mycmd '/path/with spaces/'{a,b,c}/*.gz

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

eval mycmd "'/path/with spaces/'{a,b,c}/*.gz"

P.S。然而,在这种情况下,我个人会选择一个循环来构建参数列表而不是上面显示的方法。虽然更详细,但是对于没有经验的人来说,循环会更容易阅读并且将避免使用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

答案 1 :(得分:3)

好的,所以这里有一个使用bash代表“大括号”而find代表整个小球:

find "${dirs[@]/#//path/with spaces/}" -name '*.gz' -print0 | xargs -0 mycmd

如果您需要数组中的结果,则可以使用this

答案 2 :(得分:2)

这是GNU Parallel粉丝的一个:

parallel -Xj1 mycmd {}/*.gz ::: "${dirs[@]/#//path/with spaces/}"