TL; DR: экспортируемые массивы не напрямую поддерживаются вплоть до bash-4.3, но вы можете (эффективно) экспортировать массивы одним из двух способов:
- простая модификация способа вызова дочерних сценариев
- использование экспортированной функции для хранения инициализации массива с простой модификацией дочерних сценариев
Или вы можете подождать, пока не выйдет bash-4.3 (в состоянии разработки / RC по состоянию на февраль 2014 года, см. ARRAY_EXPORT в журнале изменений). Обновление: эта функция не включено в 4.3.Если вы определите ARRAY_EXPORT
при сборке, сборка не удастся.Автор заявил , что не планируется завершать эту функцию.
Первое, что нужно понять, это то, что среда bash (точнее среда выполнения команд)) отличается от концепции среды POSIX.Среда POSIX представляет собой набор нетипизированных пар name=value
и может передаваться из процесса его дочерним элементам различными способами (фактически ограниченная форма IPC).).
Среда выполнения bash фактически является расширенной версией этого, с типизированными переменными, флагами только для чтения и экспорта, массивами, функциями и многим другим.Это отчасти объясняет, почему вывод set
(встроенный bash) и env
или printenv
отличается.
Когда вы вызываете другую оболочку bash, вы запускаете новый процесс,Вы теряете некоторое состояние Bash.Однако, если вы поставите скрипт в точку, он будет запущен в той же среде;или если вы запускаете подоболочку через ( )
, среда также сохраняется (потому что bash разветвляется, сохраняя свое полное состояние, вместо повторной инициализации с использованием среды процесса).
Ограничение, на которое ссылается ответ @ lesmana, возникает из-за того, что среда POSIX представляет собой просто name=value
пар без дополнительного значения, поэтому нет согласованного способа кодирования или форматирования типизированных переменных, интересный bash см. Ниже.Причуда в отношении функций и предстоящее изменение в bash-4.3 (предложенная функция массива отменена).
Существует несколько простых способов сделать это с помощью declare -p
(встроенный)чтобы вывести часть среды bash в виде набора из одного или нескольких операторов declare
, которые можно использовать, воссоздайте тип и значение «имени».Это базовая сериализация , но с гораздо меньшей сложностью , которую подразумевают некоторые другие ответы.declare -p
сохраняет индексы массивов, разреженные массивы и цитирование проблемных значений.Для простой сериализации массива вы можете просто выгружать значения построчно и использовать read -a myarray
для его восстановления (работает с непрерывными 0-индексированными массивами, поскольку read -a
автоматически назначает индексы).
Эти методыне требуется никаких модификаций сценария (ов), в который вы передаете массивы.
declare -p array1 array2 > .bash_arrays # serialise to an intermediate file
bash -c ". .bash_arrays; . otherscript.sh" # source both in the same environment
Вариации в приведенной выше форме bash -c "..."
иногда (неправильно) используются в crontabs для установки переменных.
Альтернативы включают:
declare -p array1 array2 > .bash_arrays # serialise to an intermediate file
BASH_ENV=.bash_arrays otherscript.sh # non-interactive startup script
Или, как однострочный:
BASH_ENV=<(declare -p array1 array2) otherscript.sh
Последний использует подстановка процесса для передачивывод команды declare
в виде сценария rc.(Этот метод работает только в bash-4.0 или более поздних версиях: более ранние версии безоговорочно fstat()
rc-файлов и используют размер, возвращаемый до read()
файл за один раз; FIFO возвращает размер 0, и поэтому не будет работать какНадеюсь.)
В неинтерактивной оболочке (то есть сценарии оболочки) файл, на который указывает переменная BASH_ENV
, автоматически получает .Вы должны убедиться, что bash вызывается правильно, возможно, используя shebang для явного вызова «bash», а не #!/bin/sh
, поскольку bash не будет учитывать BASH_ENV
в режиме истории / POSIX.
Если весь ваш массивимена имеют общий префикс, который вы можете использовать declare -p ${!myprefix*}
, чтобы расширить их список, а не перечислять их.
Вероятно, вам не следует пытаться экспортировать и повторно импортировать всю среду bash, используя этот метод, некоторые специальные переменные и массивы bash доступны только для чтения, и при изменении специальных могут быть другие побочные эффекты. переменные.
(Вы также можете сделать что-то немного неприятное, сериализовав определение массива в экспортируемую переменную и используя eval
, но давайте не будем поощрять использование eval
...
$ array=([1]=a [10]="b c")
$ export scalar_array=$(declare -p array)
$ bash # start a new shell
$ eval $scalar_array
$ declare -p array
declare -a array='([1]="a" [10]="b c")'
)
Как упоминалось выше, есть интересная особенность: специальная поддержка экспорта функций из среды:
function myfoo() {
echo foo
}
с export -f
или set +a
, чтобы включить это поведение, приведет к этому в (процессе) среде, видимой с printenv
:
myfoo=() { echo foo
}
Переменная functionname
(или functioname()
для обратной совместимости) и ее значение () { functionbody }
.
Когда запускается последующий процесс bash, он воссоздает функцию из каждой такой переменной среды. Если вы загляните в исходный файл bash-4.2 variables.c
, вы увидите, что переменные, начинающиеся с () {
, обрабатываются специально. (Хотя создание функции с использованием этого синтаксиса с declare -f
запрещено.) Обновление: Проблема безопасности " shellshock" связана с этой функцией, современные системы могут отключить автоматический импорт функций из окружающая среда как смягчение.
Если вы продолжите чтение, вы увидите защитный код #if 0
(или #if ARRAY_EXPORT
), который проверяет переменные, начинающиеся с ([
и заканчивающиеся )
, и комментарий, в котором указано " Переменные массива может быть еще не экспортировано". Хорошей новостью является то, что в текущей версии разработки bash-4.3rc2 возможность экспорта индексированных массивов (не ассоциативно) включена . Эта функция вряд ли будет включена, как отмечалось выше.
Мы можем использовать это для создания функции, которая восстанавливает любые необходимые данные массива:
% function sharearray() {
array1=(a b c d)
}
% export -f sharearray
% bash -c 'sharearray; echo ${array1[*]}'
Итак, аналогично предыдущему подходу, вызовите дочерний скрипт с помощью:
bash -c "sharearray; . otherscript.sh"
Или вы можете условно вызвать функцию sharearray
в дочернем скрипте, добавив в какой-то подходящий момент:
[ "`type -t sharearray`" = "function" ] && sharearray
Обратите внимание, что в функции sharearray
нет declare -a
, если вы сделаете так, что массив неявно local для функции, что не то, что нужно. bash-4.2 поддерживает declare -g
, что явно делает переменную глобальной, так что (declare -ga
) может быть использовано тогда. (Поскольку для ассоциативных массивов требуется declare -A
, вы не сможете использовать этот метод для ассоциативных массивов до bash-4.2.) Документация по GNU parallel
имеет полезную вариацию этого метода, см. Обсуждение --env
на справочной странице .
Ваш сформулированный вопрос также указывает на то, что у вас могут быть проблемы с самим export
. Вы можете экспортировать имя после того, как вы его создали или изменили. «exportable» - это флаг или свойство переменной, для удобства вы также можете установить и экспортировать в одном выражении. До bash-4.2 export
ожидается только имя, поддерживаются либо простая (скалярная) переменная, либо имя функции.
Даже если бы вы могли (в будущем) экспортировать массивы, экспорт выбранных индексов (среза) может не поддерживаться (хотя, так как массивы редки, нет причин, по которым это нельзя было бы разрешить). Хотя bash также поддерживает синтаксис declare -a name[0]
, индекс игнорируется, а «name» - это просто обычный индексированный массив.