In Bourne like shell which support array variable, we can use some parsing to check if variable is an array.

All commands below were run after running a=(1 2 3).


$ declare -p a
typeset -a a
a=( 1 2 3 )


$ declare -p a
declare -a a='([0]="1" [1]="2" [2]="3")'


$ typeset -p a
typeset -a a=(1 2 3)

pdksh and its derivative:

$ typeset -p a
set -A a
typeset a[0]=1
typeset a[1]=2
typeset a[2]=3


$ typeset -p a
a=('1' '2' '3')
typeset a

An example in bash:

if declare -p var 2>/dev/null | grep -q 'declare -a'; then
  echo array variable

This approach is too much work and need to spawn a subshell. Using other shell builtin like =~ in [[ ... ]] do not need a subshell, but is still too complicated.

Is there easier way to accomplish this task?

  • Under what circumstances would you need to check whether your variables are arrays or not?
    – Kusalananda
    Dec 20, 2018 at 10:07

9 Answers 9


I don't think you can, and I don't think it actually makes any difference.

unset a
echo "${a[0]-not array}"


That does the same thing in either of ksh93 and bash. It looks like possibly all variables are arrays in those shells, or at least any regular variable which has not been assigned special attributes, but I didn't check much of that.

The bash manual talks about different behaviors for an array versus a string variable when using += assignments, but it afterwards hedges and states that the the array only behaves differently in a compound assignment context.

It also states that a variable is considered an array if any subscript has been assigned a value - and explicitly includes the possibility of a null-string. Above you can see that a regular assignment definitely results in a subscript being assigned - and so I guess everything is an array.

Practically, possibly you can use:

[ 1 = "${a[0]+${#a[@]}}" ] && echo not array

...to clearly pinpoint set variables that have only been assigned a single subscript of value 0.

  • So I guess checking if ${a[1]-not array} can do the task, can't it?
    – cuonglm
    Nov 28, 2015 at 4:58
  • @cuonglm - Well, not according to the bash manual: An array variable is considered set if a subscript has been assigned a value. The null string is a valid value. If any subscript is assigned its an array per spec. In practice, also no, because you can do a[5]=x. I guess [ 1 -eq "${#a[@]}" ] && [ -n "${a[0]+1}" ] could work.
    – mikeserv
    Nov 28, 2015 at 5:03

So you effectively want just the middle part of declare -p without the junk around it?

You could write a macro such as:

readonly VARTYPE='{ read __; 
       case "`declare -p "$__"`" in
            "declare -a"*) echo array;; 
            "declare -A"*) echo hash;; 
            "declare -- "*) echo scalar;; 
         } <<<'

so that you can do:

b=( array ) 
declare -A c; c[hashKey]=hashValue;
eval "$VARTYPE" a #scalar
eval "$VARTYPE" b #array
eval "$VARTYPE" c #hash

(A mere function won't do if you'll want to use this on function-local variables).

With aliases

shopt -s expand_aliases
alias vartype='eval "$VARTYPE"'

vartype a #scalar
vartype b #array
vartype c #hash
  • @mikeserv Good point. Aliases make it look prettier. +1 Nov 28, 2015 at 19:41
  • i meant - alias vartype="$VARTYPE"... or just not defining the $VARTYPE at all - it should work, right? you only should need that shopt thing in bash because it breaks with the spec regarding alias expansion in scripts.
    – mikeserv
    Nov 28, 2015 at 19:42
  • 1
    @mikeserv I'm sure cuonglm is well capable of tweaking this approach to his needs and preferences. ;-) Nov 28, 2015 at 19:46
  • ... and security considerations. Nov 28, 2015 at 19:47
  • At no point does the above code eval user provided text. It's no less secure than a function. I've never seen you fussing about making functions read-only, but OK, I can mark the variable readonly. Nov 28, 2015 at 20:06

In zsh

zsh% a=(1 2 3) s=1
zsh% [[ ${(t)a} == *array* ]] && echo array
zsh% [[ ${(t)s} == *array* ]] && echo array
  • Maybe echo ${(t)var} is simpler. Thanks for this.
    – user79743
    Nov 28, 2015 at 21:00

To test variable var, with


It is possible to test if there are more than one array index:

[[ $c > 1 ]] && echo "Var is an array"

If the first index value is not zero:

[[ ${b[0]} -eq 0 ]] && echo "Var is an array"      ## should be 1 for zsh.

The only hard confusion is when there is only one index value and that value is zero (or one).

For that condition, it is possible to use a side effect of trying to remove an array element from a variable that is not an array:

**bash** reports an error with             unset var[0]
bash: unset: var: not an array variable

**zsh** also reports an error with         $ var[1]=()
attempt to assign array value to non-array

This works correctly for bash:

# Test if the value at index 0 could be unset.
# If it fails, the variable is not an array.
( unset "var[0]" 2>/dev/null; ) && echo "var is an array."

For zsh the index may need to be 1 (unless a compatible mode is active).

The sub-shell is needed to avoid the side effect of erasing index 0 of var.

I have found no way to make it work in ksh.

Edit 1

This function only works in bash4.2+

    case "$(typeset -p "$varname")" in
        "declare -a"*|"typeset -a"*)    echo array; ;;
        "declare -A"*|"typeset -A"*)    echo hash; ;;
        "declare -- "*|"typeset "$varname*| $varname=*) echo scalar; ;;

var=( foo bar );  getVarType var

Edit 2

This also work only for bash4.2+

{ typeset -p var | grep -qP '(declare|typeset) -a'; } && echo "var is an array"

Note: This will give false positives if var contains the tested strings.

  • How about array with zero elements?
    – cuonglm
    Nov 28, 2015 at 8:32
  • 1
    Dat edit, tho. Looks very original. :D Nov 28, 2015 at 20:30
  • @cuonglm The check ( unset "var[0]" 2>/dev/null; ) && echo "var is an array." correctly reports var is an array when var has been set to var=() an array with zero elements. It acts exactly equal to declare.
    – user79743
    Nov 29, 2015 at 12:53
  • The test for scalar won't work if the scalar is exported or marked integer/lowercase/readonly... You can probably safely make it that any other non-empty output means scalar variable. I'd use grep -E instead of grep -P to avoid the dependency on GNU grep. Nov 30, 2015 at 9:30
  • @StéphaneChazelas The test (in bash) for scalar with integer and/or lowercase and /or readonly always start with -a, like this: declare -airl var='()'. Therefore the grep test will work.
    – user79743
    Nov 30, 2015 at 17:32

For bash, it's a little bit of a hack (albeit documented): attempt to use typeset to remove the "array" attribute:

$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?

(You cannot do this in zsh, it allows you to convert an array to a scalar, in bash it's explicitly forbidden.)


 typeset +A myvariable 2>/dev/null || echo is assoc-array
 typeset +a myvariable 2>/dev/null || echo is array

Or in a function, noting the caveats at the end:

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
        echo scalar

Note the use of typeset -g (bash-4.2 or later), this is required within a function so that typeset (syn. declare) doesn't work like local and clobber the value you are trying to inspect. This also does not handle function "variable" types, you can add another branch test using typeset -f if needed.

Another (nearly complete) option is to use this:

          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.

There's one slight problem though, an array with a single subscript of 0 matches two of the above conditions. This is something that mikeserv also references, bash really doesn't have a hard distinction, and some of this (if you check the Changelog) can be blamed on ksh and compatibilty with how ${name[*]} or ${name[@]} behave on a non-array.

So a partial solution is:

if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
    echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then 
    echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]]; 
    echo is-array    

I have used in the past a variation on this:

while read _line; do
   if [[ $_line =~ ^"declare -a" ]]; then 
done < <( declare -p )

this too needs a subshell though.

One more possibly useful technique is compgen:

compgen -A arrayvar

This will list all indexed arrays, however associative arrays are not handled specially (up to bash-4.4) and appear as regular variables (compgen -A variable)

  • The typeset +a also reports an error in ksh. Not in zsh, though.
    – user79743
    Nov 28, 2015 at 20:38

Short answer:

For the two shells that introduced this notation (bash and ksh93) a scalar variable is just an array with a single element.

Neither needs a special declaration to create an array. Just the assignment is enough, and a plain assignment var=value is identical to var[0]=value.

  • Try: bash -c 'unset var; var=foo; typeset -p var'. Do bash answer report an array (needs an -a)?. Now compare with: bash -c 'unset var; var[12]=foo; typeset -p var'. Why is there a difference?. A: The shell maintains (for good or for bad) a notion of which vars are scalars or arrays. The shell ksh do mix both concepts into one.
    – user79743
    Nov 29, 2015 at 23:23

yash's array builtin has some options that only work with array variables. Example: the -d option will report an error on non-array variable:

$ a=123
$ array -d a
array: no such array $a

So we can do something like this:

is_array() (
  array -d -- "$1"
) >/dev/null 2>&1

a=(1 2 3)
if is_array a; then
  echo array

if ! is_array b; then
  echo not array

This approach won't work if array variable is readonly. Trying to modify a readonly variable leading to an error:

$ a=()
$ readonly a
$ array -d a
array: $a is read-only


[[ "$(declare -pa)" =~ [^[:alpha:]]$var= ]]

case "$?" in 
      echo "$var is an array variable"
      echo "$var is not an array variable"
      echo "Unknown exit code"

In newer versions of bash (4.4+), you can just use the attribute operator on the variable expansion.


declare -A rob

echo ${bob@a}
>>> a
echo ${rob@a}
>>> A

Note simply declaring the associative array will not print its attribute -- you must assign something to it first.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .