Преобразовать массив в аргументы команды?

40

У меня есть массив «опций» команды.

my_array=(option1 option2 option3)

Я хочу вызвать эту команду в скрипте bash, используя значения из массива в качестве параметров. Итак, command $(some magic here with my_array) "$1"становится:

command -option1 -option2 -option3 "$1"

Как я могу это сделать? Является ли это возможным?

Кто-то все еще использует тебя MS-DOS
источник
1
Таким образом, вы хотите добавить -в начало каждого слова в my_array?
Кевин
@ Кевин: Да, и выполнить его. Все строки находятся внутри одного скрипта bash. Я спрашиваю об этом, потому что эти же опции будут использоваться во многих местах внутри скрипта, поэтому вместо того, чтобы копировать их все, я подумал о массиве.
Кто-то все еще использует тебя MS-DOS
1
Это может показаться бессмысленным, но если вы создаете большие сценарии оболочки, возможно, вам стоит заняться perl, такого рода вещи очень легко сделать.
alfa64

Ответы:

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
manatwork
источник
Если я правильно понимаю, эта подстановка переменных не может быть заключена в функцию или назначена переменной, верно? Это должно идти непосредственно в вызове команды.
Конрад Рудольф
1
@KonradRudolph, вы можете присвоить его другой переменной до тех пор , как вы делаете это как присвоение массива: somevar=("${my_array[@]/#/-}")(Обратите внимание на круглые скобки вокруг значения.) Тогда, конечно , вы должны держать его обработки в виде массива при его использовании: echo "${somevar[@]}". Что касается функций, то здесь вы слишком ограничены возможностями языка. Вы можете передать массив: somefunc "${my_array[@]/#/-}", то внутри вы будете иметь его в $@: function somefunc() { echo "$@"; }. Но он также $@будет содержать другие параметры, если таковые существуют, и никакой другой способ вернуть измененный массив, кроме stdout.
manatwork
Как ни странно, не работает с Zsh. В первый раз я наткнулся на то, что работает в Bash, но не Zsh.
Привет-ангел
@ Привет, Ангел, ты уверен, что использовал @подстрочный индекс? Я дал ему тест с zsh 5.5.1, и единственное отличие, которое я заметил, это то, что zsh добавлял префикс к каждому элементу, когда записывался как ${my_array[@]/#/-}, в то время как bash делал это и для *подстрочного индекса.
manatwork
Ой, извини, я мог что-то напортачить, у меня действительно работает!
Привет-ангел
2

Я не обработал это, это было в массиве и думало отделенное пробелом в строке. Это решение будет работать с этим, но, учитывая, что это массив, используйте решение manatwork ( @{my_array[@]/#/-}).


Это не так уж и плохо с sedнедоработкой. Насколько легко это регулярное выражение, зависит от того, что вы можете гарантировать о вариантах. Если все варианты - это одно «слово» ( a-zA-Z0-9только), тогда достаточно простого начального слова border ( \<):

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

Если в ваших опциях есть другие символы (скорее всего -), вам понадобится нечто более сложное:

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

^соответствует началу строки, [ \t]соответствует пробелу или табуляции, \|соответствует любой стороне ( ^или [ \t]), \( \)группам (для \|) и сохраняет результат, \<соответствует началу слова. \1начинает замену, сохраняя первое совпадение от parens ( \(\)), и, -конечно, добавляет черту, которая нам нужна.

Они работают с GNU SED, если они не работают с вашим, дайте мне знать.

И если вы будете использовать одну и ту же вещь несколько раз, вы можете просто рассчитать ее один раз и сохранить:

opts="$(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g')"
...
command $opts "$1"
command $opts "$2"
Kevin
источник
Это не работает с Mac OS X sed, поэтому мне нужно было использовать gsed(я установил с помощью homebrew). И еще: вместо того echo $my_array, echo ${my_array[@]}чтобы получить все предметы , мне нужно было сделать my_array: echo $my_arrayдавал мне только первый элемент. Но спасибо за ответ и объяснение регулярного выражения, особенно о «границе слова», это чрезвычайно полезно. :)
Кто-то все еще использует тебя MS-DOS
Я хотел бы выйти из сценария, если система sed не совместима с этой функцией ограничения слов. Как бы я это сделал? Распечатываете версию sed и сравниваете ее? Из какой версии sed эта функция была добавлена?
Кто-то все еще использует тебя MS-DOS
1
@ SomebodystillusesyouMS-DOS Моя первая мысль - напрямую проверить, работает ли он - [ $(echo x | sed 's/\</y/') == "yx" ] || exit.
Кевин
2
Это сломается, если какой-либо из элементов массива будет содержать специальные символы, наиболее очевидно и неумолимо пропуски.
Жиль "ТАК ... перестать быть злым"
1
@ SomebodystillusesyouMS-DOS Жиль прав, вы должны изменить свое согласие на manatwork.
Кевин
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'

источник