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在变量之前扩展括号.我曾尝试过使用echo和ls甚至eval(*shudder*)的技巧,但很难让它们与文件名中的空格一起使用. find似乎没有多大帮助,因为它没有做括号.我可以为数组中的每个目录获取一个单独的glob:
dirs=( "${dirs[@]/#//path/with spaces/}" )
dirs=( "${dirs[@]/%//*.gz}" )
Run Code Online (Sandbox Code Playgroud)
但随后bash在扩展时引用了通配符.
那么:是否有一种优雅的方法可以使所有文件与变量括号和glob模式匹配,正确处理空间,还是我坚持做循环?如果这有所作为,我正在使用Bash 3.
要在带空格的路径上执行大括号扩展和通配,您可以引用包含空格的路径部分,例如
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
好的,这里是使用 bash 作为“大括号”和find通配符的一个:
find "${dirs[@]/#//path/with spaces/}" -name '*.gz' -print0 | xargs -0 mycmd
Run Code Online (Sandbox Code Playgroud)
如果您需要数组中的结果,这很有用。