将数组转换为命令的参数?


39

我有一个命令的“选项”数组。

my_array=(option1 option2 option3)

我想使用数组中的值作为选项在bash脚本中调用此命令。因此,command $(some magic here with my_array) "$1"变为:

command -option1 -option2 -option3 "$1"

我该怎么做?可能吗?


1
因此,您要添加-到in中每个单词的开头my_array吗?
凯文(Kevin)2012年

@Kevin:是的,执行它。所有行都在同一bash脚本中。我问这个问题是因为这些相同的选项将在脚本中的很多地方使用,所以我想到了一个数组,而不是复制所有这些选项。
有人仍在使用您MS-DOS

1
看起来似乎没有意义,但是如果您要编写大型的Shell脚本,也许您应该研究一下perl,在这种情况下很容易做到。
alfa64 2012年

Answers:


43

我更喜欢一个简单的bash方法:

command "${my_array[@]/#/-}" "$1"

原因之一是空格。例如,如果您有:

my_array=(option1 'option2 with space' option3)

sed基础的解决方案将改变它在-option1 -option2 -with -space -option3(长度5),但上述bash扩展将其转化为-option1 -option2 with space -option3(长度仍然3)。很少,但有时这很重要,例如:

bash-4.2$ my_array=('Ffoo bar' 'vOFS=fiz baz')
bash-4.2$ echo 'one foo bar two foo bar three foo bar four' | awk "${my_array[@]/#/-}" '{print$2,$3}'
 two fiz baz three

如果我理解正确,则不能将这种变量替换包装到函数中,也不能将其分配给变量,对吗?它需要直接进入命令调用。
康拉德·鲁道夫

1
@KonradRudolph,您可以将其分配给其他变量,只要您将其作为数组赋值即可:(somevar=("${my_array[@]/#/-}")请注意该值的括号。)然后,当使用它时,您当然必须将其作为数组处理echo "${somevar[@]}"。在功能方面,您受语言可能性的限制。您可以传递一个数组:somefunc "${my_array[@]/#/-}",然后在其中将其包含在$@:中function somefunc() { echo "$@"; }。但是$@,如果存在,同一个参数也将包含其他参数,除了stdout之外,没有其他方法可以返回修改后的数组。
manatwork

奇怪的是,不适用于zsh。我第一次偶然发现了一种可以在bash上运行但不适用于zsh的功能。
Hi-Angel

@ Hi-Angel,确定要用作@数组下标吗?我使用zsh 5.5.1进行了测试,唯一的区别是我注意到zsh在以编写时仅为每个项目添加前缀${my_array[@]/#/-},而bash也在下标中添加了前缀*
manatwork

哦,对不起,我可能已经搞砸了,确实对我有用!
Hi-Angel

2

我没有处理它在数组中,而是在考虑将空格分隔为字符串。该解决方案可以使用该解决方案,但是考虑到它是一个数组,请使用manatwork的解决方案(@{my_array[@]/#/-})。


sed和subshel​​l 并不太差。正则表达式的难易程度取决于您对选项的保证。如果所有选项都是一个“单词”(a-zA-Z0-9仅),则简单的起始单词边界(\<)就足够了:

command $(echo $my_array | sed 's/\</-/g') "$1"

如果您的选项还有其他字符(最有可能是-),则需要更复杂的东西:

command $(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g') "$1"

^匹配行的开头,[ \t]匹配空格或制表符,\|匹配任一侧(^[ \t]),匹配\( \)组(用于\|)并存储结果,\<匹配单词的开头。 \1通过保持括号(\(\))中的第一个匹配项开始替换-,当然还要添加我们需要的破折号。

这些与gnu sed一起使用,如果它们与您的不兼容,请告诉我。

而且,如果您将多次使用同一事物,则可能只需要计算一次并存储它:

opts="$(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g')"
...
command $opts "$1"
command $opts "$2"

这不适用于Mac OS X sed,因此我需要使用gsed(我使用安装了homebrew)。另一件事:代替echo $my_array,我需要做的echo ${my_array[@]}是从中获取所有项目my_arrayecho $my_array仅给我第一个元素。但是,感谢您对正则表达式的回答和解释,特别是关于“单词边界”的解释,这非常有用。:)
有人仍在使用您的MS-DOS

如果系统的sed与该字边界功能不兼容,我想退出脚本。我该怎么办?打印sed版本并进行比较?从哪个版本的sed添加了此功能?
有人仍在使用您的MS-DOS,

1
@ SomebodystillusesyouMS-DOS我的第一个想法是直接检查它是否有效- [ $(echo x | sed 's/\</y/') == "yx" ] || exit
凯文(Kevin)

2
如果任何数组元素包含特殊字符(最明显且不可避免地为空格),则此操作将中断。
吉尔(Gilles)“所以,别再邪恶了”

1
@ SomebodystillusesyouMS-DOS Gilles是正确的,您应该将接受更改为操作。
凯文(Kevin)

0
[srikanth@myhost ~]$ sh sample.sh 

-option1 -option2 -option3

[srikanth@myhost ~]$ cat sample.sh

#!/bin/bash

my_array=(option1 option2 option3)

echo ${my_array[@]} | sed 's/\</-/g'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.