Para o bash , é um pouco complicado (embora documentado): tente usar typeset
para remover o atributo "array":
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(Você não pode fazer isso zsh
, pois permite converter uma matriz em um escalar, bash
pois é explicitamente proibido.)
Então:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Ou em uma função, observando as advertências no final:
function typeof() {
local _myvar="$1"
if ! typeset -p $_myvar 2>/dev/null ; then
echo no-such
elif ! typeset -g +A $_myvar 2>/dev/null ; then
echo is-assoc-array
elif ! typeset -g +a $_myvar 2>/dev/null; then
echo is-array
else
echo scalar
fi
}
Observe o uso de typeset -g
(bash-4.2 ou posterior), isso é necessário em uma função para que typeset
(syn. declare
) Não funcione como local
e derrube o valor que você está tentando inspecionar. Isso também não lida com os tipos de "variáveis" da função, você pode adicionar outro teste de ramificação usando, typeset -f
se necessário.
Outra opção (quase completa) é usar isso:
${!name[*]}
If name is an array variable, expands to the list
of array indices (keys) assigned in name. If name
is not an array, expands to 0 if name is set and
null otherwise. When @ is used and the expansion
appears within double quotes, each key expands to a
separate word.
Há um pequeno problema, porém, uma matriz com um único índice subscrito de 0 corresponde a duas das condições acima. Isso é algo que o mikeserv também faz referência, o bash realmente não tem uma distinção difícil, e parte disso (se você verificar o Changelog) pode ser atribuída ao ksh e à compatibilidade com como ${name[*]}
ou ${name[@]}
se comportar em um não array.
Portanto, uma solução parcial é:
if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then
echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]];
echo is-array
fi
Eu usei no passado uma variação sobre isso:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
isso também precisa de um subshell.
Uma técnica possivelmente mais útil é compgen
:
compgen -A arrayvar
Isso listará todas as matrizes indexadas, no entanto, matrizes associativas não são tratadas especialmente (até o bash-4.4) e aparecem como variáveis regulares ( compgen -A variable
)