Para bash , es un truco (aunque documentado): intente usar typesetpara eliminar el atributo "array":
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(No puede hacer esto zsh, le permite convertir una matriz a un escalar, ya bashque está explícitamente prohibido).
Entonces:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
O en una función, observando las advertencias al 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
}
Tenga en cuenta el uso de typeset -g(bash-4.2 o posterior), esto es necesario dentro de una función para que typeset(syn. declare) No funcione como localy bloquee el valor que está tratando de inspeccionar. Esto tampoco maneja los tipos de función "variable", puede agregar otra prueba de ramificación utilizando typeset -fsi es necesario.
Otra opción (casi completa) es usar esto:
${!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.
Sin embargo, hay un pequeño problema: una matriz con un solo subíndice de 0 coincide con dos de las condiciones anteriores. Esto es algo a lo que mikeserv también hace referencia, bash realmente no tiene una distinción difícil, y algo de esto (si marca el registro de cambios) puede atribuirse a ksh y a la compatibilidad con cómo ${name[*]}o ${name[@]}comportarse en una no matriz.
Entonces, una solución parcial es:
if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then
echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]];
echo is-array
fi
He usado en el pasado una variación de esto:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
Sin embargo, esto también necesita un subshell.
Una técnica posiblemente más útil es compgen:
compgen -A arrayvar
Esto enumerará todas las matrices indexadas, sin embargo, las matrices asociativas no se manejan especialmente (hasta bash-4.4) y aparecen como variables regulares ( compgen -A variable)