W przypadku bash jest to trochę hack (choć udokumentowane): spróbuj użyć, typeset
aby usunąć atrybut „array”:
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(Nie możesz tego zrobić w zsh
, pozwala to przekonwertować tablicę na skalar, bash
jest to wyraźnie zabronione).
Więc:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Lub w funkcji, zwracając uwagę na ostrzeżenia na końcu:
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
}
Zwróć uwagę na użycie typeset -g
(bash-4.2 lub nowszy), jest to wymagane w ramach funkcji, aby typeset
(syn. declare
) Nie działało podobnie jak local
i blokowało wartość, którą próbujesz sprawdzić. To również nie obsługuje typów funkcji „zmiennych”, możesz dodać kolejny test gałęzi, używając w typeset -f
razie potrzeby.
Inną (prawie pełną) opcją jest użycie tego:
${!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.
Jest jednak jeden niewielki problem: tablica z pojedynczym indeksem 0 odpowiada dwóm powyższym warunkom. Jest to coś, do czego mikeserv również się odwołuje, bash tak naprawdę nie ma twardego rozróżnienia, a niektóre z nich (jeśli zaznaczysz Dziennik zmian) można winić za ksh i zgodność z tym, jak ${name[*]}
lub jak się ${name[@]}
zachowywać na nie-macierzy.
Więc częściowe rozwiązanie jest:
if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then
echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]];
echo is-array
fi
W przeszłości korzystałem z tej wersji:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
to też potrzebuje podpowłoki.
Jeszcze jedną potencjalnie przydatną techniką jest compgen
:
compgen -A arrayvar
Spowoduje to wyświetlenie listy wszystkich indeksowanych tablic, jednak tablice asocjacyjne nie są obsługiwane specjalnie (do wersji bash-4.4) i pojawiają się jako zmienne zwykłe ( compgen -A variable
)