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.