使用printf命令将字符写入N次


12

我发现以下命令在Linux中重复一个字符:

printf 'H%.0s' {1..5000} > H.txt

例如,我想H重复5000一次。这%.0s是什么意思?


使用tcshzshrepeat 5000 printf H更容易理解。随着perlprint "H" x 5000(注意,{1..5000}是灵感的zsh运营商perl1..5000一个,后来被ksh93的和bash复制)
斯特凡Chazelas

是的,它可以工作,但是需要大量资源进行较大的重复,请遵循StéphaneChazelas的建议
Skaperen 2015年

1
我会执行此命令yes H|head -5000|tr -d '\012'
Skaperen 2015年

dd if=/dev/zero bs=5000 count=1 | tr '\0' H
kojiro 2015年

@Skaepren:yes H| head -n 2500| tr \\n H
mikeserv

Answers:


20

该命令取决于shell生成5000个参数,然后将其传递给它们printf,然后忽略它们。尽管它看起来非常快-并且相对于某些事情而言-shell仍必须将所有这些字符串生成为args (并对其进行定界),依此类推。

除了生成的Hs在外壳程序第一次迭代到5000之前无法打印的事实之外,该命令还消耗了存储和将数字字符串参数定界并printf 加上 Hs 所需的全部内存。就像您可以做到的一样:

printf %05000s|tr \  H

...这将生成一个由5000个空格组成的字符串-至少每个空格通常只有一个字节,并且无需花费任何定界费用,因为它们没有定界。一些测试表明,即使在只有5000个字节的tr情况下,即使在这种情况下,fork和所需的管道的成本也是值得的,而且几乎总是在数字增加时。

我跑了

time bash -c 'printf H%.0s {1..5000}' >/dev/null

...和...

time bash -c 'printf %05000s|tr \  H' >/dev/null

每次大约5次(这里没什么科学意义-只是轶事),而括号扩展版本的平均总处理时间为.02秒多一点,但该tr版本平均平均大约为.012秒- tr击败了它每次。我不能说我很惊讶-这{brace expansion}是一个有用的交互式Shell速记功能,但是在涉及任何类型的脚本时,这通常是一件相当浪费的事情。常见形式:

for i in {[num]..[num]}; do ...

...当您考虑时,实际上是两个 for循环-第一个是内部循环,这意味着外壳程序必须以某种方式循环以生成那些迭代器,然后再保存所有迭代器并为for循环再次对其进行迭代。这样的事情通常更好地完成,例如:

iterator=$start
until [ "$((iterator+=interval))" -gt "$end" ]; do ...

...因为您只存储了很少的值,并且在生成可迭代对象时进行迭代以及执行过程中都将其覆盖。

无论如何,就像前面提到的空格填充一样,您当然也可以使用printf零填充任意数量的数字,例如:

printf %05000d

我都没有参数,因为对于printf找不到格式参数的格式字符串中指定的每个参数,都使用null字符串-对于数字参数,它解释为零,对于字符串,则解释为空字符串。

与问题中的命令相比,这是硬币的另一面(在我看来,这是更有效的一面),但是,当您printf %.0为每个参数加长字符串时,可能无法从中得到任何东西,所以也是有可能一事无成。

仍然可以更快地使用大量生成的字节,dd例如:

printf \\0| dd bs=64k conv=sync 

...和带有常规文件ddseek=[num]参数可以用于更大的优势。如果添加,unblock cbs=1到上面,则可以获得64k换行符,而不是null ,然后可以使用paste/dev/null- 从那里每行注入任意字符串,但是在这种情况下,如果您可以使用它,则也可以使用:

yes 'output string forever'

dd无论如何,这里还有更多示例:

dd bs=5000 seek=1 if=/dev/null of=./H.txt

......它创建(或截断)一个\0NUL名为H.txt的大小5000个字节当前目录填充文件。dd直接寻找偏移量,然后将其后的NUL填满。

<&1 dd bs=5000 conv=sync,noerror count=1 | tr \\0 H >./H.txt

...这将创建一个相同名称和大小的文件,但带有H字符。它利用了dd'spec'的行为,即在指定了noerrorsync转换时(如果没有count=-进行的时间可能比您想要的更长),在发生读取错误的情况下,至少写出一个完整的空块,并且有意地进行重定向位于ddstdin 的只写文件描述符。


8

%.0s机构的说法转换为字符串,具有精确的零。根据man 3 printf,在这种情况下的精度值给出

   [ ... ] the  maximum  number  of characters to be printed from a
   string for s and S conversions.

因此,当精度为零时,根本不会输出string参数。然而,H(这是格式说明的一部分)获取打印多次有参数,根据自printfman bash

The format is reused as necessary to consume all  of  the  argu
ments.  If the format requires more arguments than are supplied,
the extra format specifications behave as if  a  zero  value  or
null  string,  as  appropriate,  had  been supplied. 

7

在这种情况下,请%.0s始终打印字符前面的一个实例,在这种情况下为H。当您使用{1..5000}时,shell将其展开,它将变为:

printf 'H%.0s' 1 2 3 4 ... 5000 > H.txt

也就是说,printf命令现在具有5000个参数,并且对于每个参数,您将获得一个H。这些不必是顺序的或数字的:

printf 'H%.0s' a bc fg 12 34

打印HHHHH-即参数个数,在这种情况下为5。

请注意,上面第一个示例中的省略号不是按字面意思插入的,它们用来指示序列或范围。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.