使用 printf 命令写入一个字符 N 次

使用 printf 命令写入一个字符 N 次

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

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

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

答案1

该命令取决于 shell 生成 5000 个参数,并将它们传递给printfshell,然后忽略它们。虽然它可能看起来相当快 - 并且与某些事情相关 - shell 仍然必须生成所有这些字符串作为 args(并界定它们)等等。

除了在 shell 第一次迭代到 5000 之前无法打印生成的 Hs 之外,该命令还会消耗内存来存储和分隔数字字符串参数printf Hs。正如您可以做的那样:

printf %05000s|tr \  H

...它生成一个包含 5000 个空格的字符串 - 至少每个空格通常只有一个字节,并且不需要任何分隔成本,因为它们没有分隔。一些测试表明,即使在这种情况下,即使只有 5000 字节,所需的分叉和管道的成本tr也是值得的,而且几乎总是在数字变得更高时。

我跑了...

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

...和...

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

每个约5次一个(这里没有什么科学依据——只是轶事)大括号扩展版本的平均总处理时间略多于 0.02 秒,但该tr版本的平均总处理时间约为 0.012 秒 - 并且该tr版本每次都击败了它。我不能说我感到惊讶 -{brace expansion}是一个有用的交互式 shell 速记功能,但对于任何类型的脚本编写来说通常都是相当浪费的事情。常见形式:

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

……仔细想想,真的是 for循环 - 第一个是内部的,暗示 shell 必须以某种方式循环来生成这些迭代器,然后再保存所有迭代器并为循环再次迭代它们for。这些事情通常更好做,例如:

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

...因为您只存储很少的值并在生成可迭代时进行迭代并在使用时覆盖它们。

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

printf %05000d

我都在没有参数的情况下执行这两个操作,因为对于 的格式字符串中指定的每个参数,printf当找不到参数时,将使用空字符串 - 它被解释为数字参数的零或字符串的空字符串。

这是另一个(而且 - 在我看来 - 更有效率)与问题中的命令相比,这是硬币的一面 - 虽然有可能像printf %.0为每个参数长度字符串一样从某些东西中得到任何东西,所以也有可能从无到有得到一些东西。

对于大量生成的字节,您可以使用更快的方法,dd例如:

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

...并且使用常规文件ddseek=[num]参数可以发挥更大的优势。如果你添加,unblock cbs=1到上面,你可以得到 64k 换行符而不是空值,并且从那里可以用pasteand为每行注入任意字符串/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时发生读取错误时至少写出一个完整的空块noerrorsync(并且 - 如果没有count=- 可能会持续比你想要的更长的时间)dd,并故意重定向 的stdin处的只写文件描述符。

答案2

%.0s参数转换为细绳,有一个精确为零。根据man 3 printf,这种情况下的精度值给出

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

因此当精度为零时,字符串参数根本没有打印。然而,H(它是格式说明符的一部分)会被打印与参数一样多的次数,因为printf根据man 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. 

答案3

在这种情况下,%.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。

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

相关内容