用 NULL 将 stdin 填充到所需长度的最佳方法

Gel*_*ler 2 shell printf text-formatting

我有以下要求。我有一个输入流,需要将其截断为某个固定长度的字节。我事先不知道输入流的长度。如果流的长度小于设置的长度,我想用零字节填充它。我尝试使用truncate,但显然它只能处理文件,不能处理标准输入。

例如,假设我们的输入流 (stdin) 是TEST,并且我们希望达到 10 个字节的长度。那么输出流(stdout)应该是TEST\x00\x00\x00\x00\x00.

为了澄清这一点,该示例是使用小字符串完成的,但结果对于大流(兆字节到千兆字节)应该表现良好。另外我目前使用的容器是基于Ubuntu的。

Sté*_*las 5

使用 GNU dd

\n
$ printf %s test | dd iflag=fullblock bs=10 status=none conv=sync count=1 | hexdump -C\n00000000  74 65 73 74 00 00 00 00  00 00                    |test......|\n0000000a\n
Run Code Online (Sandbox Code Playgroud)\n

对于zsh,使用其right 填充(和截断)参数扩展标志(以及p用于转义序列的标志,例如\\0在填充字符串中扩展):

\n
$ string=test\n$ printf %s ${(pr[10][\\0])string} | hexdump -C\n00000000  74 65 73 74 00 00 00 00  00 00                    |test......|\n0000000a\n
Run Code Online (Sandbox Code Playgroud)\n

但请注意,它会填充 10 个字符,而不是 10 个字节。您可以关闭该multibyte选项来更改它 ( set +o multibyte)。

\n
$ string=t\xc3\xa9st\n$ printf %s ${(pr[10][\\0])string} | hexdump -C\n00000000  74 c3 a9 73 74 00 00 00  00 00 00                 |t..st......|\n0000000b\n$ printf %s ${(pr[10][\\0])string} | wc -mc\n     10      11\n
Run Code Online (Sandbox Code Playgroud)\n
$ set +o multibyte\n$ printf %s ${(bpr[10][\\0])string} | hexdump -C\n00000000  74 c3 a9 73 74 00 00 00  00 00                    |t..st.....|\n0000000a\n$ printf %s ${(bpr[10][\\0])string} | wc -mc\n      9      10\n
Run Code Online (Sandbox Code Playgroud)\n

这些解决方案无法很好地扩展到大于系统 RAM 量的大小。

\n

对于大尺寸,正如 @ilkkachu 在评论中建议的那样,

\n
{ printf %s test; cat /dev/zero; } | head -c 1000000000\n
Run Code Online (Sandbox Code Playgroud)\n

会更高效(不是标准的,但很常见,并且比一次读写一个字节head -c要高效得多)。dd bs=1

\n

如果输出到文件,您还可以使用资源限制来进行截断:

\n
(\n  ulimit -f 1048576 # KiB\n  printf %s test\n  cat /dev/zero\n) > file\n
Run Code Online (Sandbox Code Playgroud)\n