10

Using printf, one can print a character multiple times:

$ printf "%0.s-" {1..5}
-----

In awk I know that I can do something like:

$ awk 'BEGIN {while (i++ < 5) printf "-"}'
-----

But I wonder if awk's printf allows this as well.

I went through the printf modifiers page but could not find how. All in all, what the printf from Bash does is to expand {1..5} and print a - for every parameter it gets, so it is equivalent to saying

$ printf "%0.s-" hello how are you 42
-----

However, I lack the knowledge on how to mimic this behaviour with awk's printf, if it is possible, because this fails:

$ awk 'BEGIN {printf "%0.s-", 1 2 3 4 5}'
-
Community
  • 1
  • 1
fedorqui
  • 252,262
  • 96
  • 511
  • 570

3 Answers3

13

I do not believe this is possible with awk's printf, as there is also no way to do this just with printf in C and C++.

With awk, I think the most reasonable option is using a loop like you have. If for some reason performance is vital and awk is creating a bottleneck, the following will speed things up:

awk 'BEGIN {s=sprintf("%5s","");gsub(/ /,"-",s);print s}'

This command will run logarithmically faster[1] Though, it won't cause a noticeable difference in performance unless you're planning on printing a character many times. (Printing a character 1,000,000 times will be about 13x faster.)

Also, if you want a one-liner and are using gawk, even though it's the slowest of the bunch:

gawk 'BEGIN {print gensub(/ /,"-","g",sprintf("%5s",""));}'

 

[1] While the sprintf/gsub command should always be faster than using a loop, I'm not sure if all versions of awk will behave the same as mine. I also do not understand why the while-loop awk command would have a time complexity of O(n*log(n)), but it does on my system.

Community
  • 1
  • 1
Jeffrey Cash
  • 973
  • 5
  • 12
  • 3
    Brilliant! Could you share the insight on how you got to know the time complexity? I timed `awk 'BEGIN {while (i++ < 1000000) printf "-"}'` and `awk 'BEGIN {s=sprintf("%1000000s","");gsub(/ /,"-",s);print s}'` and the difference was 0.102s vs 0.115s. – fedorqui May 19 '16 at 05:57
  • 1
    Absolutely. I wrote a bash function to benchmark four different awk commands: the while-loop one, the `gsub` one, the `gensub` one, and a control that only printed a single dash. This function tested all of the commands against a wide variety of lengths of inputs and repetitions, subtracting the dummy time from the other three. From this, I found that the gensub one was much slower than the rest, so I focused just on while vs gsub. I then took my data and played around with it with wolframalpha, custom math functions and a google sheet, leading me to those big-O values. – Jeffrey Cash May 19 '16 at 09:55
  • [Here is one of the google sheets](https://docs.google.com/spreadsheets/d/1P8neMgoyJf34uoV1JtQ3hiEZuL0LWnl55z0zTXjwJ-E/edit?usp=sharing), in case you're curious. It's the only part of the process I still have left – Jeffrey Cash May 19 '16 at 10:01
8

I know this is old but the width modifier can be used e.g.

l = some_value

print gensub(/ /, "-", "g", sprintf("%*s", l, ""))

will print a variable number of - depending on the value of l

This was GNU Awk 3.1.8

anubhava
  • 713,503
  • 59
  • 514
  • 593
Maurice1408
  • 309
  • 2
  • 7
2

If you can assume a (modest) upper bound on how long the result should be, how about something like this:

l = 5;
print substr("---------------------", 1, l);

Besides being dead simple, this has the benefit that it works in versions of AWK that lack the "gensub()" function.

user98761
  • 420
  • 3
  • 8