Для bash , це трохи хак (хоч і задокументовано): спроба використовувати typesetдля видалення атрибута "масив":
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(Ви не можете цього зробити zsh, це дозволяє перетворити масив у скаляр, вbash оскільки це явно заборонено.)
Так:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Або у функції, зазначивши застереження в кінці:
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
}
Зверніть увагу на використання typeset -g(bash-4.2 або пізнішої версії), це потрібно в рамках функції, щоб typeset(синх. declare) Не працювало так localі не обмежувало значення, яке ви намагаєтеся перевірити. Це також не обробляє функції "змінних" типів, ви можете додати ще один тест гілки, використовуючи, typeset -fякщо потрібно.
Ще одним (майже повним) варіантом є використання цього:
${!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.
Однак є одна незначна проблема: масив з одним підрозділом 0 відповідає двом з перерахованих вище умов. Це те, на що mikeserv також посилається, bash насправді не має жорсткого розрізнення, і дещо з цього (якщо ви перевіряєте Журнал змін) можна звинуватити в ksh та сумісності з тим, як ${name[*]}чи${name[@]} поводитись у не масиві.
Отже, часткове рішення:
if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then
echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]];
echo is-array
fi
Раніше я використовував варіацію цього:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
для цього теж потрібна нижня оболонка.
Ще одна корисна методика compgen:
compgen -A arrayvar
У цьому списку будуть перераховані всі індексовані масиви, однак асоціативні масиви не обробляються спеціально (до bash-4.4) і відображаються як регулярні змінні ( compgen -A variable)