Para bash , es un truco (aunque documentado): intente usar typeset
para 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 bash
que 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 local
y 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 -f
si 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
)