Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I pass an array to awk using -v?

I would like to be able to pass an array variable to awk. I don't mean a shell array but a native awk one. I know I can pass scalar variables like this:

awk -vfoo="1" 'NR==foo' file

Can I use the same mechanism to define an awk array? Something like:

$  awk -v"foo[0]=1" 'NR==foo' file
awk: fatal: `foo[0]' is not a legal variable name

I've tried a few variations of the above but none of them work on GNU awk 4.1.1 on my Debian. So, is there any version of awk (gawk,mawk or anything else) that can accept an array from the -v switch?

I know I can work around this and can easily think of ways to do so, I am just wondering if any awk implementation supports this kind of functionality natively.

like image 227
terdon Avatar asked Oct 13 '15 14:10

terdon


3 Answers

You can use the split() function inside mawk or gawk to split the input of the "-v" value (here is the gawk man page):

split(s, a [, r [, seps] ])

Split the string s into the array a and the separators array seps on the regular expression r, and return the number of fields.*

An example here in which i pass the value "ARRAYVAR", a comma separated list of values which is my array, with "-v" to the awk program, then split it into the internal variable array "arrayval" using the split() function and then print the 3rd value of the array:

echo 0 | gawk -v ARRAYVAR="a,b,c,d,e,f" '{ split(ARRAYVAR,arrayval,","); print(arrayval[3]) }'
c

Seems to work :)

like image 104
rmicmir Avatar answered Sep 27 '22 19:09

rmicmir


It looks like it is impossible by definition.

From man awk we have that:

-v var=val

--assign var=val

Assign the value val to the variable var, before execution of the program begins. Such variable values are available to the BEGIN rule of an AWK program.

Then we read in Using Variables in a Program that:

The name of a variable must be a sequence of letters, digits, or underscores, and it may not begin with a digit.

Variables in awk can be assigned either numeric or string values.

So the way the -v implementation is defined makes it impossible to provide an array as a variable, since any kind of usage of the characters = or [ is not allowed as part of the -v variable passing. And both are required, since arrays in awk are only associative.

like image 31
fedorqui 'SO stop harming' Avatar answered Sep 27 '22 20:09

fedorqui 'SO stop harming'


If you don't insist on using -v you could use -i (include) instead to read an awk file that contains the variable settings. Like this:

if F=$(mktemp inputXXXXXX); then
    cat >$F << 'END'
BEGIN {
    foo[0]=1
}
END
cat $F
    awk -i $F 'BEGIN { print foo[0] }' </dev/null
    rm $F
fi

Sample trace (using gawk-4.2.1):

bash -x /tmp/test.sh 
++ mktemp inputXXXXXX
+ F=inputrpMsan
+ cat
+ cat inputrpMsan
BEGIN {
    foo[0]=1
}
+ awk -i inputrpMsan 'BEGIN { print foo[0] }'
1
+ rm inputrpMsan
like image 33
U. Windl Avatar answered Sep 27 '22 20:09

U. Windl