Bei Bash handelt es sich um einen kleinen Hack (wenn auch dokumentiert): Versuchen Sie typeset
, das Attribut "array" zu entfernen:
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(Dies ist nicht möglich. Sie können zsh
ein Array in einen Skalar konvertieren, da bash
dies ausdrücklich verboten ist.)
So:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Oder in einer Funktion, die Vorbehalte am Ende beachten:
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
}
Beachten Sie die Verwendung von typeset -g
(bash-4.2 oder höher). Dies ist in einer Funktion erforderlich, damit typeset
(syn. declare
) Nicht wie local
der Wert funktioniert und den Sie untersuchen möchten. Dies gilt auch nicht für Funktionstypen mit "Variablen". Sie können typeset -f
bei Bedarf einen weiteren Verzweigungstest hinzufügen .
Eine weitere (fast vollständige) Option besteht darin, Folgendes zu verwenden:
${!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.
Es gibt jedoch ein kleines Problem: Ein Array mit einem einzelnen Index von 0 entspricht zwei der oben genannten Bedingungen. Dies ist etwas, worauf mikeserv auch hinweist, bash hat wirklich keine harte Unterscheidung, und einige davon (wenn Sie das Changelog überprüfen) können auf ksh und die Kompatibilität mit dem Verhalten ${name[*]}
oder ${name[@]}
Verhalten auf einem Nicht-Array zurückgeführt werden.
Also a Teillösung ist also:
if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then
echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]];
echo is-array
fi
Ich habe in der Vergangenheit eine Variation davon verwendet:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
Auch das braucht eine Unterschale.
Eine weitere möglicherweise nützliche Technik ist compgen
:
compgen -A arrayvar
Dadurch werden alle indizierten Arrays aufgelistet. Assoziative Arrays werden jedoch nicht speziell behandelt (bis zu bash-4.4) und erscheinen als reguläre Variablen ( compgen -A variable
).