Для 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
)