bashdynamicawk

Does awk support dynamic user-defined variables?


awk supports this:

awk '{print $(NF-1);}'

but not for user-defined variables:

awk '{a=123; b="a"; print $($b);}'

by the way, shell supports this:

a=123;
b="a";
eval echo \${$b};

How can I achieve my purpose in awk?


Solution

  • Not at the moment. However, if you provide a wrapper, it is (somewhat hacky and dirty) possible. The idea is to use @ operator, introduced in the recent versions of gawk.

    This @ operator is normally used to call a function by name. So if you had

    function foo(s){print "Called foo "s}
    function bar(s){print "Called bar "s}
    {
        var = "";
        if(today_i_feel_like_calling_foo){
            var = "foo";
        }else{
            var = "bar";
        }
        @var( "arg" ); # This calls function foo(), or function bar() with "arg"
    }
    

    Now, this is usefull on it's own. Assuming we know var names beforehand, we can write a wrapper to indirectly modify and obtain vars

    function get(varname, this, call){call="get_"varname;return @call();}
    function set(varname, arg, this, call){call="set_"varname; @call(arg);}
    

    So now, for each var name you want to prrvide access by name, you declare these two functions

    function get_my_var(){return my_var;}
    function set_my_var(arg){my_var = arg;}
    

    And prahaps, somewhere in your BEGIN{} block,

    BEGIN{ my_var = ""; }
    

    To declare it for global access. Then you can use

    get("my_var");
    set("my_var", "whatever");
    

    This may appear useless at first, however there are perfectly good use cases, such as keeping a linked list of vars, by holding the var's name in another var's array, and such. It works for arrays too, and to be honest, I use this for nesting and linking Arrays within Arrays, so I can walk through multiple Arrays like using pointers.

    You can also write configure scripts that refer to var names inside awk this way, in effect having a interpreter-inside-a-interpreter type of things, too...

    Not the best way to do things, however, it gets the job done, and I do not have to worry about null pointer exceptions, or GC and such :-)