Back in February, I wrote about printing out a separator in Bash. At the time, I thought its a bit pain in the butt, but when I encountered punchcard.awk and tried to save a few LOC, AWK is even more painful. There is no string repetition nor Brace Expansion.

1   Solutions

These are how you can do it:

BEGIN {
  LENGTH = 40;
  # AWK
  sep = sprintf("%*s", LENGTH, "");
  gsub(/ /, "-", sep);
  print "start <", sep, "> end";
  # GNU AWK
  print gensub(/0/, "-", "g", sprintf("start < %0*d > end", LENGTH, 0));
  # Really, seriously?
  printf("start < ");
  for (i=0; i<LENGTH; i++) {
    printf("-");
  }
  printf(" > end\n");
}
start < ---------------------------------------- > end
start < ---------------------------------------- > end
start < ---------------------------------------- > end

If you use GNU AWK, then you can have a real one-liner, however, its still looks a bit weird for me.

The methods are different in two cases above, one uses %d, the other uses %s. They are very much the same, only %d with 0 padding can be very useful if the separator has some extra stuff with, same may not be same with space padding.

2   Speedtest

2.1   AWK

time awk -e 'BEGIN {
  LENGTH = 58;
  for (i=0; i<1000; i++) {
    sep = sprintf("%*s", LENGTH, "");
    gsub(/ /, "-", sep);
    print sep;
  }
}' >/dev/null
real    0m0.022s
user    0m0.020s
sys     0m0.002s

2.2   GNU AWK

time awk -e 'BEGIN {
  LENGTH = 58;
  for (i=0; i<1000; i++) {
    print gensub(/ /, "-", "g", sprintf("%*s", LENGTH, ""));
  }
}' >/dev/null
real    0m0.020s
user    0m0.018s
sys     0m0.001s

2.3   Really, seriously?

time awk -e 'BEGIN {
  LENGTH = 58;
  for (i=0; i<1000; i++) {
    printf("start < ");
    for (j=0; j<LENGTH; j++) {
      printf("-");
    }
    printf(" > end\n");
  }
}' >/dev/null
real    0m0.024s
user    0m0.023s
sys     0m0.000s

2.4   Bash

I picked one of fastest methods from the post for Bash, there are more way of what you can do in Bash.

time for i in {1..1000}; do printf -v sep '%*s' 58 ; echo "${sep// /-}" >/dev/null ; done
real    0m0.080s
user    0m0.073s
sys     0m0.006s

Clearly, no doubt that AWK beats Bash. ~20ms over ~80ms.

3   Thought

AWK is an interesting language, sometimes I like it, sometimes I dont. When you have written same task in different languages, you always feel something is missing in a language.

There is nothing wrong with Really, seriously? method and to be frankly, it is more readable and clearer than using gsub or gensub. Just you would feel its as if you were still doing some exercise in the text book, you know like how to use loop.

Will I use those, certainly will for sakes of LOC and already have. There are not really too hard to understand and not overly ugly in my opinion. And most importantly, they are fastest methods, though looping method itself doesnt look bad at all.