por que uma variável de matriz não é considerada definida se for designada '()'?

1

manual do bash diz:

A parameter is an entity that stores values

A variable is a parameter denoted by a name.

A parameter is set if it has been assigned a value.

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

Uma variável de matriz é uma variável e um parâmetro?

Se sim, por que uma variável de matriz não é considerada configurada se for atribuída () ?

$ ar=()
$ echo ${ar-This is a new value}
This is a new value

Obrigado.

    
por Tim 24.07.2017 / 19:44

3 respostas

4

Em bash , como em ksh , em que $var é uma matriz, $var é realmente a abreviação de ${var[0]} .

Então, em:

var=([1]=whatever [2]=blah)

${var+set} não se expandiria para set e [[ -v var ]] retornaria falso, porque $var não tem elemento de indice 0 (observe que em bash , como em ksh , mas ao contrário da maioria outras shells e linguagens, arrays são sparse arrays ou arrays associativos com chaves limitadas a inteiros positivos).

Em bash (pelo menos desde 4.3), quando você declara uma variável como matriz com:

typeset -a var

var é inicialmente não definido. Não está nem mesmo definido para uma lista vazia. Em 4.3 , typeset -p var retornaria um erro. Em 4.2 e antes, ele produziria:

declare -a a='()'

(como se declarasse a matriz com uma lista vazia como em zsh )

Em 4.4, gera:

declare -a var

Portanto, desde a versão 4.3, uma matriz não definida (mas declarada) é diferente de uma matriz que é atribuída a uma lista vazia.

Ainda assim, é difícil diferenciar programaticamente entre os dois. Mas na prática, a distinção não é muito útil. Provavelmente, o que você deseja saber é quantos elementos estão na matriz:

((${#array[@]})) || echo array has no element

Veja zsh , rc , fish e yash para shells com melhores designs de matriz.

    
por 24.07.2017 / 20:06
1

A construção ${var-foo} é expandida para foo se var não estiver definida ou nula . Uma matriz vazia é exatamente isso.

Como você cita:

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

O exemplo do seu site ( ar=() ) não atribui um valor a nenhum subscrito.

    
por 24.07.2017 / 19:49
1

A maneira correta de testar uma matriz inteira é:

[[ ${ar[@]+set} == set ]] && echo "array has a value may be a null"

O que você escreveu é o teste para o valor no índice 0. Esses dois são equivalentes:

${ar+set}
${ar[0]+set}

Mas ambos testarão apenas se a matriz no índice zero está definida ou não, e não a matriz inteira, o que suponho ser o que você quis dizer.

Mas, para sua pergunta: Por que uma matriz não está definida se asigned ()?

Porque você não atribuiu qualquer valor, nem mesmo o valor nulo, a nenhum índice de matriz.
Para obter algum índice a ser definido (e, consequentemente, o array), você precisa de algo como:

$ declare -a ar=([3]="value")

Ou até mesmo:

$ declare -a ar=([3]="")

zsh (mesmo em emulação sh ou ksh) é o único de todos os shells testados (como de costume, o especial) que declara um array como definido com:

$ unset ar; typeset -a ar=(); echo $(typeset -p ar) ${ar[@]+set}

Pergunta dos comentários:

Thanks. Can ar[@] be replaced with ar[*] here? Are they array variables?

Não, um "${ar[*]}" é a concatenação de string de todos os valores da matriz.

No entanto, nesta expansão específica: "$ {ar [*] + set}" ambos são equivalentes.

Do manual (em matrizes):

If subscript is @ or *, the word expands to all members of name.

    
por 25.07.2017 / 01:52