почему переменная массива не считается установленной, если ей присвоено `()`?

Хотя я полностью согласен с возможностью повторного использования , удобочитаемостью и деликатно целовать боссов, но есть еще одно преимущество функций в : область видимости переменной . Как 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.

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

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

2
24.07.2017, 20:52
3 ответа

Конструкция ${var-foo}расширяется до foo, если varне установлено или имеет значение null . Пустой массив — это именно то, что нужно.

Как вы цитируете:

An array variable is considered set if a subscript has been assigned a value.

Пример, который вы размещаете (ar=()), не присваивает значение ни одному индексу.

2
27.01.2020, 21:52

В 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для оболочек с лучшей конструкцией решетки.

4
27.01.2020, 21:52

Правильный способ проверки всего массива:

[[ ${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.

2
27.01.2020, 21:52

Теги

Похожие вопросы