1

I'm working on an AWK script that quite a big mess at the moment, and I'm trying to improve it (primarily because I want to improve my Awk scripting skillz)

I realize that there isn't a way to do Object Oriented Programming within Awk or Gawk, but is there a way to at least curry functions? As in returning a function from within a function? (Not return the result of the executed function, but rather return a function that can be executed)

I found a Stack Overflow post, where @GreenFox showed that its possible to execute a function with the name of the function stored in a variable. The example he posted is below:

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"
}

What I'm wondering is if its possible to return a function from another function.

For example, a function that accepts a string that can be used in awks printf as a format, and returns a function that accepts two other arguments, and essentially executes printf( fmt_from_parent_func, sub_func_arg1, sub_func_arg2 ).

Here's my attempt at trying to accomplish the following:

#! /usr/local/bin/awk -f

function setFmt ( fmt ){
  function _print ( var, val ){
    printf ( fmt ? fmt : "%-15s: %s\n" ), str1, str2
  }
  return @_print
}
BEGIN {
  fmtA = setFmt("%-5s: %s\n")
  @fmtA("ONE","TWO")
}

Which results in the errors:

awk: ./curry.awk:4:   function _print ( var, val ){
awk: ./curry.awk:4:   ^ syntax error
awk: ./curry.awk:4:   function _print ( var, val ){
awk: ./curry.awk:4:                               ^ syntax error
awk: ./curry.awk:6:     printf ( fmt ? fmt : "%-15s: %s\n" ), str1, str2
awk: ./curry.awk:6:                                                     ^ unexpected newline or end of string
awk: ./curry.awk:11:   fmtA = setFmt("%-5s: %s\n")
awk: ./curry.awk:11:                              ^ unexpected newline or end of string
awk: ./curry.awk:12:   @fmtA("ONE","TWO")
awk: ./curry.awk:12:                     ^ unexpected newline or end of string

If anyone knows if this is at all possible (which Im starting to see myself), and knows a way to accomplish something to this effect.. that would be awesome.

Thanks!

Community
  • 1
  • 1
Justin
  • 1,959
  • 5
  • 22
  • 40

1 Answers1

2

With GNU awk you can return the name of a function as a string from another function but you can't declare a function within another function nor can you return a function (or an array) in any awk - all you can return from a function in awk is a scalar value (i.e. a number or string).

Is this what you're trying to do:

$ cat tst.awk
function _print ( var, val ){
  printf _print_fmt, var, val
}

function setFmt ( fmt ){
  _print_fmt = (fmt ? fmt : "%-15s: %s\n" )
  return "_print"
}

BEGIN {
  fmtA = setFmt("%-5s: %s\n")
  @fmtA("ONE","TWO")
}

$ awk -f tst.awk
ONE  : TWO
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • Not quite. It looks like there isnt a way to accomplish this, due to Awk functions not being stateful. – Justin Jan 30 '17 at 22:09
  • Can you elaborate on "not quite"? What does the code I posted need to do that it doesn't do? Barring that, if you can show us what you're trying to do (as opposed to how you're trying to do it) with concise, testable sample input and expected output then I'm sure someone can help you to do whatever it is you're trying to do idiomatically in awk. – Ed Morton Jan 30 '17 at 22:52