Comportamento estranho de matrizes não inicializadas e matrizes não definidas

7

Estou escrevendo um script e descobri um comportamento inesperado de variáveis de array não inicializadas e não definidas que não entendo.

Primeiro de tudo, o tamanho:

$ echo ${#notset[@]}
0
$ uninitialized=
$ echo ${#uninitialized[@]}
1

Por que o uninitialized length 1? Não deveria ser zero? É porque uma variável nula é considerada uma matriz de um elemento nulo?

Este fato leva a alguns problemas. Por exemplo, suponha que eu queira criar uma matriz e inserir um determinado número de itens com base nos argumentos da linha de comando do usuário. Eu pensei que poderia fazer algo como (+) :

myarray=

if [ some-condition ]
then
    myarray[${#myarray[@]}]=some-value
fi

if [ some-condition2 ]
then
    myarray[${#myarray[@]}]=some-value2
elif [ some-condition3 ]
then
    myarray[${myarray[@]}]=some-value3
    myarray[${myarray[@]}]=some-value4
fi

Mas isso deixa o primeiro slot para null, o qual eu não gosto e também quebra algum código que eu escrevi (*) , e neste momento suponho que eu quero ver se o array contém qualquer elemento. Como devo fazer isso?

[ -z "${myarray[@]}" ]

Gera um erro se a matriz contiver mais de um elemento.

[ -z "$myarray" ]

Falha porque o primeiro elemento é nulo, mesmo que a matriz não esteja vazia.

Então, como devo controlar que um array não seja inicializado?

E alguém poderia explicar o que exatamente acontece ao lidar com arrays e variáveis não inicializadas não configuradas?

(+) Eu sei que eu poderia evitar "declarar" a variável e isso funcionaria, mas esse script será revisado por um professor, e ele não gosta de variáveis sendo definidas em lugares aleatórios .

(*) Antes de tentar esta coisa eu estava mantendo o comprimento da matriz em uma outra variável, e assim eu não tive problemas. Mas eu gostaria de evitar definir essas variáveis auxiliares, pois sei que posso obter o tamanho sem elas.

    
por Bakuriu 26.10.2012 / 19:03

2 respostas

11

Você pode ver a diferença com declare -p :

unset foo
declare -a foo
declare -p foo
# prints declare -a foo='()'
foo=
declare -p foo
# prints declare -a foo='([0]="")'

Se você deseja inicializar um array vazio, a saída do primeiro declare -p é uma boa dica sobre a melhor maneira de declará-lo:

declare -a array='()'

(A parte declare -a é provavelmente opcional, um array=() simples deve funcionar também.)

Se você quiser testar se uma matriz possui 0 elementos, use a comparação numérica em ${#array[@]} ; não tente fazer um test -z na expansão, pois não dará o resultado correto em muitos casos.

    
por 26.10.2012 / 19:16
8

Para inicializar um array vazio, use

array=()

Para adicionar um valor ao array, use

array+=(value)
    
por 26.10.2012 / 19:26

Tags