Передать ассоциативный массив как список параметров в скрипт

9

В скрипте у меня есть ассоциативный массив, как:

declare -A VARS=( ["key1"]="value1" ["key2"]="value" )

Есть ли одна команда, чтобы преобразовать это в список параметров в форме

--key1=value1 --key2=value2

без необходимости переписывать вручную

 --key1="${VARS[key1]}" --key2="${VARS[key2]}"

вариант использования, который я имел в виду, состоял в том, чтобы передать массив скрипту в виде списка параметров, например

my_script.sh $(to_param_list $VARS)

Чтобы развернуть комментарий, который я сделал к ответу @Kusalananda, мой точный пример использования следующий: у меня есть скрипт, который используется для построения самораспаковывающегося установщика с использованием makeself, и этот скрипт получает некоторые параметры, которые должны быть разделены между:

  • параметры для самого скрипта
  • параметры для установщика внутри самораспаковывающегося установщика

Затем сценарии собирают установщик следующим образом:

to_param_list installer_param_list installer_param_array
./makeself ./path/to/sourcedir ./path/to/created/installer "My installer" ./path/to/install/inside/package "${installer_param_list[@]}"

Тем не менее, я протестировал передачу параметров с помощью очень простого установочного скрипта внутри пакета:

while ! -z "$1" ; do
    echo "$1"
    shift
done

и передать массив как:

installer_param_array=( ["upgrade-from"]="19 .2.0" ["upgrade-to"]="19.3.0" )

Результаты в этом выводе:

--upgrade-to=19.3.0
--upgrade-from=19
.2.0
Маттео Тассинари
источник
Это не отвечает на вопрос, но другой способ (в bash, один из тегов) есть my_script.sh "$(declare -p thearray)$". В myscript.sh вы читаете это с source /dev/stdin <<<"$1"Тогда у вас есть thearrayв вашем сценарии. Вы можете иметь другие аргументы рядом с массивом. Вы можете передать много переменных: my_script.sh "$(declare -p var1 var2 ...)"в этом единственном аргументе.
Dominic108

Ответы:

13

С вспомогательной функцией:

#!/bin/bash

to_param_list () {
    declare -n outlist=$1
    declare -n inhash=$2

    for param in "${!inhash[@]}"; do
        outlist+=( "--$param=${inhash[$param]}" )
    done
}

declare -A my_vars=( ["key1"]="value1" ["key2"]="value" )

to_param_list list my_vars
my_script.sh "${list[@]}"

Последняя команда в приведенном выше сценарии будет расширена до эквивалента написания

my_script.sh "--key2=value" "--key1=value1"

to_param_listФункция принимает имя переменного массива и имя ассоциативного массива переменного и использует их , чтобы создать два «эталонное название» переменные в функции (namerefs были введены в bashвыпуске 4.3). Затем они используются для заполнения заданной переменной массива ключами и значениями в соответствующем формате из ассоциативного массива.

Цикл в функции повторяется "${!inhash[@]}", и это список ключей, заключенных в отдельные кавычки в вашем ассоциативном массиве.

Как только вызов функции вернется, скрипт будет использовать массив для вызова другого вашего скрипта или команды.

Запуск выше с

declare -A my_vars=( ["key1"]="hello world" ["key2"]="some thing" ["key3"]="* * *" )

to_param_list list my_vars
printf 'Arg: %s\n' "${list[@]}"

скрипт выведет

Arg: --key2=some thing
Arg: --key3=* * *
Arg: --key1=hello world

Это показывает, что параметры генерируются без разделения слов или ввода имени файла в действие. Это также показывает, что порядок ключей может не сохраняться, так как доступ к ключам из ассоциативного массива будет делать это в довольно случайном порядке.


Вы не можете использовать безопасную подстановку команд здесь, так как результатом будет одна строка. Если не заключено в кавычки, эта строка будет разделена на пробельные символы (по умолчанию), что дополнительно разделит и ключи, и значения вашего ассоциативного массива. Оболочка также будет выполнять поиск имени файла в результирующих словах. Двойные кавычки подстановки команд не помогли бы, так как это привело бы к вызову your my_script.shс одним аргументом.


Что касается вашей проблемы сmakeself :

makeselfСкрипт делает это с аргументами к установщику сценарию:

SCRIPTARGS="$*"

Это сохраняет аргументы в виде строки в $SCRIPTARGS(сцепленные, разделенные пробелами). Это позже вставляется в самораспаковывающийся архив как есть. Чтобы параметры были правильно проанализированы при их повторной оценке (как это происходит при запуске программы установки), вам необходимо будет указать дополнительный набор кавычек в значениях параметров, чтобы они были правильно разделены.

installer_param_array=( ["upgrade-from"]="'19 .2.0'" ["upgrade-to"]="'19.3.0'" )

Обратите внимание, что это не ошибка в моем коде. Это всего лишь побочный эффект makeselfсоздания шелл-кода на основе предоставленных пользователем значений.

В идеале makeselfсценарий должен был написать каждый из предоставленных аргументов с дополнительным набором кавычек вокруг них, но это не так, предположительно, потому что трудно понять, какой эффект это может иметь. Вместо этого он предоставляет пользователю дополнительные цитаты.

Перезапустив мой тест сверху, но теперь с

declare -A my_vars=( ["key1"]="'hello world'" ["key2"]="'some value'" ["key3"]="'* * *'" )

to_param_list list my_vars
printf 'Arg: %s\n' "${list[@]}"

производит

Arg: --key2='some value'
Arg: --key3='* * *'
Arg: --key1='hello world'

Вы можете видеть, что эти строки при повторной оценке оболочкой не разбиваются на пробелы.

Очевидно, что вы можете использовать свой исходный ассоциативный массив и вместо этого добавить кавычки в to_param_listфункцию, изменив

outlist+=( "--$param=${inhash[$param]}" )

в

outlist+=( "--$param='${inhash[$param]}'" )

В любой из этих изменений в код будет включать в себя одиночные кавычки в значениях параметров, поэтому переоценка ценностей стала бы необходимой .

Кусалананда
источник
Я попробовал ваше решение, однако, если одно из значений в начальном ассоциативном массиве содержит пробел, результирующая команда будет
Маттео
@ MatteoTassinari Нет, не будет. Если это так, значит, вы забыли двойные кавычки в "--$param=${inhash[$param]}"или в "${list[@]}", или скрипт, который получает параметры, что-то делает не так при их разборе.
Кусалананда
Я могу подтвердить, что я использовал кавычки, как вы показываете, эти параметры передаются на github.com/megastep/makeself для создания установщика, который при выполнении вызывает скрипт с заданными параметрами, возможно, в этом отрывке что-то пойдет не так
Маттео
1
Нет, это не так, я попытаюсь отредактировать свой вопрос, чтобы лучше показать мой вариант использования.
Маттео
1
Я добавил свой фактический вариант использования и ошибку, которая у меня
Маттео