我有一些文件看起来像:
/path/with spaces/{a,b,c}/*.gz
并且我需要所有匹配 a,b,c
目录子集下的 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。
最佳答案
要在带空格的路径上执行大括号扩展和通配,您可以引用路径中包含空格的部分,例如
mycmd '/path/with spaces/'{a,b,c}/*.gz
使用变量值列表进行大括号扩展有点棘手,因为大括号扩展是在任何其他扩展之前完成的。除了使用可怕的 eval
,我看不出有什么办法。
eval mycmd "'/path/with spaces/'{a,b,c}/*.gz"
附言然而,在这种情况下,我个人会选择循环来构建参数列表,而不是上面显示的方法。虽然更冗长,但对于外行来说,循环将更容易阅读,并且将避免使用 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
关于Bash:在文件名中用空格扩展大括号和 globs?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14381711/