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

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

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

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

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

答案1

使用 GNU dd

$ printf %s test | dd iflag=fullblock bs=10 status=none conv=sync count=1 | hexdump -C
00000000  74 65 73 74 00 00 00 00  00 00                    |test......|
0000000a

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

$ string=test
$ printf %s ${(pr[10][\0])string} | hexdump -C
00000000  74 65 73 74 00 00 00 00  00 00                    |test......|
0000000a

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

$ string=tést
$ printf %s ${(pr[10][\0])string} | hexdump -C
00000000  74 c3 a9 73 74 00 00 00  00 00 00                 |t..st......|
0000000b
$ printf %s ${(pr[10][\0])string} | wc -mc
     10      11
$ set +o multibyte
$ printf %s ${(bpr[10][\0])string} | hexdump -C
00000000  74 c3 a9 73 74 00 00 00  00 00                    |t..st.....|
0000000a
$ printf %s ${(bpr[10][\0])string} | wc -mc
      9      10

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

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

{ printf %s test; cat /dev/zero; } | head -c 1000000000

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

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

(
  ulimit -f 1048576 # KiB
  printf %s test
  cat /dev/zero
) > file

答案2

我找到了以下解决方案:

echo -n 'TEST' | cat - /dev/zero | dd bs=1 count=10 2>/dev/null | hexdump

这有效并正确输出以下内容:

0000000 4554 5453 0000 0000 0000
000000a

所以这至少在 Linux 上对我有用,而且我不关心跨平台可移植性。但我觉得可能有一些命令比dd实现我的目标更适合。

相关内容