fedorqui
fedorqui

Reputation: 290105

How to use printf to print a character multiple times?

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

Upvotes: 13

Views: 12778

Answers (4)

user2606364
user2606364

Reputation: 13

i know this post is old, but thought it would be worth demonstrating functionality to allow dynamic control of character string length using basic awk.

A simple example incorporating a string of length 'var' into a printf statement

$ echo "1 foo baa\n2 baa foo" | awk -v var=6 'BEGIN{for(i=1;i<=var;i++) l=l "-" }{printf "%s" l "%s" l "%s\n",$1,$2,$3}' 
1------foo------baa
2------baa------foo

You can either split the format string and insert your character string as I've done above. Or you can give the string it's own format specifier

$ echo "1 foo baa\n2 baa foo" | awk -v var=6 'BEGIN{for(i=1;i<=var;i++) l=l "-" }{printf "%s%s%s%s%s\n",$1,l,$2,l,$3}' 

both output the same.

A more complicated example that column justifies text. (I've actually used basic 'print' rather than 'printf' in this case, although you could use the latter, as above).

$ echo "Hi, I know this\npost is old, but thought it would be worth demonsrating\nfunctionality to allow a dynamic control of\ncharacter string lengths using basic awk." |
 
awk '{
   line[NR]=$0 ; 
   w_length[NR]=length($0)-gsub(" "," ",$0) ;  
   max=max>length($0)?max:length($0) ;  
   w_count[NR]=NF 
}END{
   for(i=1;i<=NR;i++) 
     {
     string="" ; 
     for (j=1;j<=int((max-w_length[i])/(w_count[i]-1));j++) 
        string=string "-" ; 
     gsub(" ",string,line[i]) ; 
     print line[i]
     }
}'

Hi,--------------I--------------know--------------this
post-is-old,-but-thought-it-would-be-worth-demonsrating
functionality---to---allow---a---dynamic---control---of
character---string---lengths---using---basic---awk.

Upvotes: 0

user98761
user98761

Reputation: 512

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.

Upvotes: 4

Maurice1408
Maurice1408

Reputation: 319

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

Upvotes: 9

Jeffrey Cash
Jeffrey Cash

Reputation: 1073

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.

Upvotes: 15

Related Questions