arraysvariablesawkgawkvariable-types

How to check if a variable is an array?


I was playing with PROCINFO and its sorted_in index to be able to control the array transversal.

Then I wondered what are the contents of PROCINFO, so I decided to go through it and print its values:

$ awk 'BEGIN {for (i in PROCINFO) print i, PROCINFO[i]}'
ppid 7571
pgrpid 14581
api_major 1
api_minor 1
group1 545
gid 545
group2 1000
egid 545
group3 10004
awk: cmd. line:1: fatal: attempt to use array `PROCINFO["identifiers"]' in a scalar context

As you see, it breaks because there is -at least- one item that it is also an array itself.

The fast workaround is to skip this one:

awk 'BEGIN {for (i in PROCINFO) {if (i!="identifiers") {print i, PROCINFO[i]}}}'

However it looks a bit hacky and would like to have something like

awk 'BEGIN {for (i in PROCINFO) {if (!(a[i] is array)) {print i, PROCINFO[i]}}}'
                                     ^^^^^^^^^^^^^^^^

Since there is not a thing like a type() function to determine if a variable is an array or a scalar, I wonder: is there any way to check if an element is an array?

I was thinking in something like going through it with a for and catching the possible error, but I don't know how.

$ awk 'BEGIN{a[1]=1; for (i in a) print i}'
1
$ awk 'BEGIN{a=1; for (i in a) print i}'
awk: cmd. line:1: fatal: attempt to use scalar `a' as an array
$ awk 'BEGIN{a[1]=1; print a}'
awk: cmd. line:1: fatal: attempt to use array `a' in a scalar context

Solution

  • In GNU Awk, there's an answer, but the recommended approach depends on what version you are running.


    From GNU Awk 4.2, released in October 2017, there is a new function typeof() to check this, as indicated in the release notes from the beta release:

    1. The new typeof() function can be used to indicate if a variable or array element is an array, regexp, string or number. The isarray() function is deprecated in favor of typeof().

    So now you can say:

    $ awk 'BEGIN { a[1] = "a"; print typeof(a) }'
    array
    

    And perform the check as follows:

    $ awk 'BEGIN { a = "a"; if (typeof(a) == "array") print "yes" }'    
    $ awk 'BEGIN { a[1] = "a"; if (typeof(a) == "array") print "yes" }'
    yes
    

    In older versions, you can use isarray():

    $ awk 'BEGIN { a = "a"; if (isarray(a)) print "yes" }'
    $ awk 'BEGIN { a[1] = "a"; if (isarray(a)) print "yes" }'
    yes
    

    From the man page:

    isarray(x)
        Return true if x is an array, false otherwise.