
Создает ли bash declare -a A
пустой массив A
или просто устанавливает атрибут на случай, если A
он будет назначен позже?
Рассмотрим этот код:
set -u
declare -a A
echo ${#A[*]}
echo ${A[*]}
A=()
echo ${#A[*]}
echo ${A[*]}
A=(1 2)
echo ${#A[*]}
echo ${A[*]}
Каков должен быть ожидаемый результат?
В Bash 4.3.48(1) я получаю bash: A: unbound variable
при запросе количества элементов после declare
. Я также получаю эту ошибку при доступе ко всем элементам. Я знаю, что более поздние версии Bash обрабатывают это по-другому. Все же я хотел бы знать, на declare
самом ли делеопределяетпеременная (должна быть пустой).
решение1
Это зависит от того, была ли соответствующая переменная уже объявлена в текущей области видимости (верхний уровень, то есть глобальная или текущая функция).
Если она не была объявлена в текущей области видимости (и помните, что в области видимости верхнего уровня переменная может быть объявлена)заявил(и назначается) путем импорта его из среды), затем он объявляет его (делает его локальным по отношению к функции, когда он находится в области видимости функции), назначает ему тип, но не инициализирует его, даже для пустого списка ( declare -p a
показывает declare -a a
, а не declare -a a=()
так, как если бы вы объявили и/или назначили его с помощью a=()
).
Если он уже был объявлен в текущей области действия (например, потому что он был импортирован как скалярная переменная из среды, когда находился в глобальной области действия), то declare -a a
будет предпринята попыткаконвертироватьего в массив.
Если ранее это был скаляр, то он становится ([0]=value-of-the-variable)
массивом. Если это уже был массив, то он остается нетронутым. Если это был ассоциативный массив, то он завершается ошибкой cannot convert associative to indexed array
.
Обратите внимание, что declare a
не преобразует массив или хэш в скаляр. bash
в любом случае не сможет преобразовать хэш/массив в скаляр. Вы можете использовать declare +aA a
для принудительного скаляра (это приведет к ошибке, если переменная ранее была хешем/массивом в текущей области видимости).
В вашем случае переменная, вероятно, еще не была объявлена в текущей области видимости, поэтому она была объявлена, но не назначена, что объясняет, почему попытка ее расширения в set -u
.
Это различие между двумязаявилиназначенный/наборсостояния переменной не являются специфическими для bash
. В POSIX sh
вы также можете export
переменную или создать ее, readonly
не присваивая ей значения.
$ sh -uc 'unset -v var; readonly var; : "$var"'
sh: 1: var: parameter not set
Обратите внимание, что unset
оба метода отменяют и отменяют объявление переменной. В bash
, mksh
и yash
он может восстановить переменную из внешней области видимости.
В zsh
, за исключением sh
эмуляции, использование typeset
переменной объявляет и устанавливает ее в пустое значение, если оно еще не было установлено или было установлено, но из другого типа (скалярный, массив или ассоциативный массив).