如何使用printf多次打印一个字符?

13
使用 printf 函数,可以多次打印一个字符。
$ printf "%0.s-" {1..5}
-----

awk中我知道我可以像这样做something like:

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

但我想知道 awk的printf 是否也支持这个功能。

我仔细研究了printf修饰符页面,但没有找到如何实现。总的来说,Bash的printf会展开{1..5}并为每个参数打印一个-,因此它等同于以下语句。

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

然而,我不知道如何使用awk的printf来模仿此行为(如果可能的话),因为这样做会失败:

$ awk 'BEGIN {printf "%0.s-", 1 2 3 4 5}'
-

2
嗯,Perl 也可以做到... perl -e "print '5'x60" :-) - Mark Setchell
@MarkSetchell awk并不那么聪明 :/ 无论是print "a" * 3还是print "a" x 3都不起作用。 - fedorqui
4个回答

13
我不认为在awk的printf中这是可能的,因为即使在C和C++的printf中也没有一种方法可以做到这一点
使用awk,我认为最合理的选择是像你所做的那样使用循环。如果出于某种原因性能至关重要,而awk正在创建瓶颈,则以下内容将加快速度:
awk 'BEGIN {s=sprintf("%5s","");gsub(/ /,"-",s);print s}'

这个命令会比对数函数运行要快得多[1]。不过,除非您计划多次打印字符,否则不会对性能造成明显影响。(将一个字符打印1,000,000次会快约13倍)。

此外,如果您想要一行代码并且使用gawk,则即使它是最慢的一个:

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

[1]虽然sprintf/gsub命令应该始终比使用循环更快,但我不确定所有版本的awk是否会像我的那样表现相同。我也不明白while-loop awk命令为什么会在我的系统上具有O(n*log(n))的时间复杂度。


3
太棒了!您能分享一下您是如何得知时间复杂度的洞见吗?我测试了两个命令:awk 'BEGIN {while (i++ < 1000000) printf "-"}'awk 'BEGIN {s=sprintf("%1000000s","");gsub(/ /,"-",s);print s}',发现它们的运行时间分别为0.102秒和0.115秒。 - fedorqui
1
当然。我编写了一个bash函数来对比四个不同的awk命令:while循环,gsubgensub和仅打印单破折号的控制。该函数针对各种长度的输入和重复次数测试了所有命令,并从其他三个命令中减去了虚拟时间。通过这个,我发现gensub比其他命令慢得多,所以我只关注while和gsub。然后,我使用wolframalpha、自定义数学函数和google表格来处理我的数据,得出了那些大O值。 - Jeffrey Cash
这是其中一个谷歌表格,如果你感兴趣的话可以看一下。这是我还剩下的唯一部分了。 - Jeffrey Cash

9

我知道这是旧的,但可以使用 width 修饰符,例如:

l = some_value

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

将根据l的值打印不同数量的-

这是GNU Awk 3.1.8


4

如果您能假设结果的长度有一个(适度的)上限,可以考虑如下方法:

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

除了非常简单之外,这还有一个好处是它可以在缺少 "gensub()" 函数的 AWK 版本中工作。

0

我知道这篇文章很旧,但是我认为展示使用基本的awk允许动态控制字符字符串长度的功能是值得的。

一个简单的例子将长度为'var'的字符串合并到printf语句中。

$ 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

你可以像我上面所做的那样,拆分格式字符串并插入你的字符字符串。或者你可以为该字符串提供它自己的格式说明符。

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

两者输出结果相同。

一个更复杂的例子是列对齐文本。(在这种情况下,我实际上使用了基本的“print”而不是如上所述的“printf”。)

$ 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.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接