Pour bash , c'est un peu un hack (bien que documenté): essayez d'utiliser typeset
pour supprimer l'attribut "array":
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(Vous ne pouvez pas faire cela dans zsh
, cela vous permet de convertir un tableau en scalaire, dans bash
ce qui est explicitement interdit.)
Donc:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Ou dans une fonction, en notant les mises en garde à la fin:
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
}
Notez l'utilisation de typeset -g
(bash-4.2 ou version ultérieure), ceci est requis dans une fonction pour que typeset
(syn. declare
) Ne fonctionne pas comme local
et n'encombre pas la valeur que vous essayez d'inspecter. Cela ne gère pas non plus les types de fonction "variable", vous pouvez ajouter un autre test de branche en utilisant typeset -f
si nécessaire.
Une autre option (presque complète) consiste à utiliser ceci:
${!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.
Il y a cependant un léger problème, un tableau avec un seul indice de 0 correspond à deux des conditions ci-dessus. C'est quelque chose que mikeserv fait également référence, bash n'a vraiment pas de distinction difficile, et une partie de cela (si vous vérifiez le Changelog) peut être blâmée sur ksh et compatible avec comment ${name[*]}
ou ${name[@]}
se comporter sur un non-tableau.
Une solution partielle est donc:
if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then
echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]];
echo is-array
fi
J'ai utilisé dans le passé une variation à ce sujet:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
cela aussi a besoin d'un sous-shell.
Une autre technique peut-être plus utile est compgen
:
compgen -A arrayvar
Ceci listera tous les tableaux indexés, cependant les tableaux associatifs ne sont pas traités spécialement (jusqu'à bash-4.4) et apparaissent comme des variables régulières ( compgen -A variable
)