Хотя я полностью согласен с возможностью повторного использования , удобочитаемостью и деликатно целовать боссов, но есть еще одно преимущество функций в bash : область видимости переменной . Как LDP показывает :
#!/bin/bash
# ex62.sh: Global and local variables inside a function.
func ()
{
local loc_var=23 # Declared as local variable.
echo # Uses the 'local' builtin.
echo "\"loc_var\" in function = $loc_var"
global_var=999 # Not declared as local.
# Therefore, defaults to global.
echo "\"global_var\" in function = $global_var"
}
func
# Now, to see if local variable "loc_var" exists outside the function.
echo
echo "\"loc_var\" outside function = $loc_var"
# $loc_var outside function =
# No, $loc_var not visible globally.
echo "\"global_var\" outside function = $global_var"
# $global_var outside function = 999
# $global_var is visible globally.
echo
exit 0
# In contrast to C, a Bash variable declared inside a function
#+ is local ONLY if declared as such.
Я не очень часто вижу это в реальных сценариях оболочки, но это кажется хорошей идеей для более сложных сценариев. Уменьшение согласованности помогает избежать ошибок, когда вы искажаете переменную, ожидаемую в другой части кода.
Повторное использование часто означает создание общей библиотеки функций и исходного кода
этой библиотеки во все ваши сценарии. Это не поможет им работать быстрее, но поможет вам быстрее их писать.
Конструкция ${var-foo}
расширяется до foo
, если var
не установлено или имеет значение null . Пустой массив — это именно то, что нужно.
Как вы цитируете:
An array variable is considered set if a subscript has been assigned a value.
Пример, который вы размещаете (ar=()
), не присваивает значение ни одному индексу.
В bash
, как и в ksh
, где $var
— массив, $var
на самом деле является сокращением от ${var[0]}
.
Так в:
var=([1]=whatever [2]=blah)
${var+set}
не расширится до set
, а [[ -v var ]]
вернет false, потому что $var
не имеет элемента с индексом 0 (обратите внимание, что в bash
, как и в ksh
, но в отличие от большинства других оболочки и языки, массивы — это разреженные массивы или ассоциативные массивы с ключами, ограниченными положительными целыми числами ).
В bash
(, по крайней мере, начиная с версии 4.3 ), когда вы объявляете переменную как массив с помощью:
typeset -a var
var
изначально не установлено. Он даже не установлен в пустой список. В 4.3
, typeset -p var
вернет ошибку. В версии 4.2 и раньше он выводил:
declare -a a='()'
(как если бы массиву присваивался пустой список, как вzsh
)
В 4.4 выводит:
declare -a var
Итак, начиная с версии 4.3, неустановленный (, но объявленный )массив отличается от массива, которому назначен пустой список.
Тем не менее, программно трудно провести различие между ними. Но на практике это различие не очень полезно. Скорее всего, вам нужно знать, сколько элементов в массиве:
((${#array[@]})) || echo array has no element
См. zsh
, rc
, fish
и yash
для оболочек с лучшей конструкцией решетки.
Правильный способ проверки всего массива:
[[ ${ar[@]+set} == set ]] && echo "array has a value may be a null"
То, что вы написали, является тестом для значения с индексом 0. Эти два эквивалентны:
${ar+set}
${ar[0]+set}
Но оба будут проверять только, установлен ли массив с нулевым индексом или нет, а не весь массив, что, как я полагаю, вы имели в виду.
Но на ваш вопрос :Почему массив не установлен, если он назначен ()?
Поскольку вы не присвоили какое-либо значение,даже не нуль, к любому индексу массива.
Чтобы установить некоторый индекс (и, следовательно, массив ), вам нужно что-то вроде:
$ declare -a ar=([3]="value")
Или даже:
$ declare -a ar=([3]="")
zsh (даже в эмуляции sh или ksh )единственная из всех протестированных оболочек (как обычно, специальная ), которая объявляет массив как набор с помощью:
$ unset ar; typeset -a ar=(); echo $(typeset -p ar) ${ar[@]+set}
Вопрос из комментариев:
Thanks. Can ar[@] be replaced with ar[*] here? Are they array variables?
Нет, "${ar[*]}"
— это объединение строк всех значений массива.
Однако в этом конкретном расширении :"${ar[*]+set}" оба эквивалентны.
Из руководства (в Arrays):
If subscript is @ or *, the word expands to all members of name.