Tricky brace expansion in shell

匿名 (未验证) 提交于 2019-12-03 01:48:02

问题:

When using a POSIX shell, the following

touch {quick,man,strong}ly 

expands to

touch quickly manly strongly 

Which will touch the files quickly, manly, and strongly, but is it possible to dynamically create the expansion? For example, the following illustrates what I want to do, but does not work because of the order of expansion:

TEST=quick,man,strong    #possibly output from a program echo {$TEST}ly 

Is there any way to achieve this? I do not mind constricting myself to Bash if need be. I would also like to avoid loops. The expansion should be given as complete arguments to any arbitrary program (i.e. the program cannot be called once for each file, it can only be called once for all files). I know about xargs but I'm hoping it can all be done from the shell somehow.

回答1:

... There is so much wrong with using eval. What you're asking is only possible with eval, BUT what you might want is easily possible without having to resort to bash bug-central.

Use arrays! Whenever you need to keep multiple items in one datatype, you need (or, should use) an array.

TEST=(quick man strong) touch "${TEST[@]/%/ly}" 

That does exactly what you want without the thousand bugs and security issues introduced and concealed in the other suggestions here.

The way it works is:

  • "${foo[@]}": Expands the array named foo by expanding each of its elements, properly quoted. Don't forget the quotes!
  • ${foo/a/b}: This is a type of parameter expansion that replaces the first a in foo's expansion by a b. In this type of expansion you can use % to signify the end of the expanded value, sort of like $ in regular expressions.
  • Put all that together and "${foo[@]/%/ly}" will expand each element of foo, properly quote it as a separate argument, and replace each element's end by ly.


回答2:

In bash, you can do this:

#!/bin/bash TEST=quick,man,strong eval echo $(echo {$TEST}ly) #eval touch $(echo {$TEST}ly) 

That last line is commented out but will touch the specified files.



回答3:

Taking inspiration from the answers above:

$ TEST=quick,man,strong $ touch $(eval echo {$TEST}ly) 


回答4:

Zsh can easily do that:

TEST=quick,man,strong print ${(s:,:)^TEST}ly 

Variable content is splitted at commas, then each element is distributed to the string around the braces:

quickly manly strongly 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!