我有一些看起来像的文件:
/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在变量之前扩展大括号。我曾尝试使用echo
和ls
甚至eval
(* shudder *)的技巧,但很难让它们与文件名中的空格一起使用。 find
似乎没有多大帮助,因为它没有做括号。我可以在数组中为每个目录获得一个单独的glob:
dirs=( "${dirs[@]/#//path/with spaces/}" )
dirs=( "${dirs[@]/%//*.gz}" )
然后bash在扩展时引用通配符。
所以:有没有一种优雅的方法可以让所有文件与变量括号和glob模式匹配,正确处理空格,还是我坚持做循环?我正在使用Bash 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/}"