Per bash , è un po 'un trucco (sebbene documentato): tenta di utilizzare typeset
per rimuovere l'attributo "array":
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(Non puoi farlo in zsh
, ti permette di convertire un array in uno scalare, in bash
è esplicitamente vietato.)
Così:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
O in una funzione, notando le avvertenze alla fine:
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
}
Nota l'uso di typeset -g
(bash-4.2 o successivo), questo è richiesto all'interno di una funzione in modo che typeset
(syn. declare
) Non funzioni come local
e ostruisca il valore che stai cercando di ispezionare. Anche questo non gestisce i tipi di "variabili" di funzione, è possibile aggiungere un altro test di diramazione usando typeset -f
se necessario.
Un'altra opzione (quasi completa) è di usare questo:
${!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.
Tuttavia, c'è un piccolo problema, un array con un singolo pedice di 0 corrisponde a due delle condizioni precedenti. Questo è qualcosa a cui mikeserv fa riferimento, bash in realtà non ha una netta distinzione e alcuni di questi (se si controlla il log delle modifiche) possono essere biasimati su ksh e sulla compatibilità con come ${name[*]}
o ${name[@]}
comportarsi su un non-array.
Quindi una soluzione parziale è:
if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then
echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]];
echo is-array
fi
In passato ho usato una variazione su questo:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
anche questo ha bisogno di una subshell.
Un'altra tecnica forse utile è compgen
:
compgen -A arrayvar
Verranno elencati tutti gli array indicizzati, tuttavia gli array associativi non vengono gestiti in modo speciale (fino a bash-4.4) e vengono visualizzati come variabili regolari ( compgen -A variable
)