Gel*_*ler 2 shell printf text-formatting
我有以下要求。我有一个输入流,需要将其截断为某个固定长度的字节。我事先不知道输入流的长度。如果流的长度小于设置的长度,我想用零字节填充它。我尝试使用truncate
,但显然它只能处理文件,不能处理标准输入。
例如,假设我们的输入流 (stdin) 是TEST
,并且我们希望达到 10 个字节的长度。那么输出流(stdout)应该是TEST\x00\x00\x00\x00\x00
.
为了澄清这一点,该示例是使用小字符串完成的,但结果对于大流(兆字节到千兆字节)应该表现良好。另外我目前使用的容器是基于Ubuntu的。
使用 GNU dd
:
$ 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
,使用其r
ight 填充(和截断)参数扩展标志(以及p
用于转义序列的标志,例如\\0
在填充字符串中扩展):
$ 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
)。
$ 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 ulimit -f 1048576 # KiB\n printf %s test\n cat /dev/zero\n) > file\n
Run Code Online (Sandbox Code Playgroud)\n