POSIX Array – Portable Check for Array in Awk

arrayawkgawkmawkposix

Gawk has "isarray":

if (isarray(x))
  print "is array"
else
  print "is scalar"

However Mawk and "gawk –posix" do not:

fatal: function 'isarray' not defined

This can cause problems:

x
x[1]
fatal: attempt to use scalar 'x' as an array

Or:

x[1]
x
fatal: attempt to use array 'x' in a scalar context

Can Awk detect an array without using the "isarray" function?

Best Answer

I also don't think it's possible.

But I'll add that with busybox awk, variables can be both arrays and scalar. There it's OK to do:

a = "foo"; a["foo"] = "bar"

When a variable has been used as an array though, length() returns the number of elements in the array, even if it also has been defined as a scalar (though you can use length(var "") to get the length of the scalar), except when the variable has been passed as an argument to a function and assigned as a scalar there (could be considered as a bug):

$ busybox awk 'BEGIN{a[1] = 1; a = "foo"; print length(a), length(a"")}'
1 3
$ busybox awk 'function f(x) {x = "xxx"; print x[1], length(x)}
               BEGIN{a[1]=1; x = "yyy"; print a[1], length(a); f(a)}'
1 1
1 3

Too bad as otherwise it would have been easy to define a isarray() function there. We can still tell if a variable is an array with at least one element with

function isnonemptyarray(x) {
  return length(x) > 0 && length(x "") == 0
}

(assuming the variable hasn't been defined both as an array and scalar)

In anycase, that's busybox awk specific. length() can't be used on arrays portably. One can define a portable array_length() function with:

function array_length(a, tmp1, tmp2) {
  tmp1 = 0
  for (tmp2 in a) tmp1++
  return tmp1
}

But that can't be used portably on non-array variables.

Related Question