我想写一个 CGI,它必须从 STDIN 读取指定数量的字节。我的想法是这样做:
dd bs=$CONTENT_LENGTH count=1
但我想知道,块大小是否受 RAM 以外的任何限制。
$ dd bs=1000000000000
dd: memory exhausted by input buffer of size 1000000000000 bytes (931 GiB)
GNU 的 coreutils 的手册页没有指定任何限制。
我想写一个 CGI,它必须从 STDIN 读取指定数量的字节。我的想法是这样做:
dd bs=$CONTENT_LENGTH count=1
但我想知道,块大小是否受 RAM 以外的任何限制。
$ dd bs=1000000000000
dd: memory exhausted by input buffer of size 1000000000000 bytes (931 GiB)
GNU 的 coreutils 的手册页没有指定任何限制。
POSIX 规范
dd
没有明确指定最大值,但有一些限制:size_t
要读取的字节数的类型;read
read
还指定有一个限制SSIZE_MAX
;read
只能传输 2,147,479,552 字节。在 64 位平台上,
size_t
长度为 64 位;此外,它是无符号的,因此dd
当给定值大于 2 64 – 1 时会失败:在 64 位 x86 上的 Linux 上,
SSIZE_MAX
是 0x7fffffffffffffffL(运行echo SSIZE_MAX | gcc -include limits.h -E -
检查),这就是输入限制:一旦找到一个可以接受的值,下一个限制就是可以分配的内存量,因为
dd
需要先分配一个缓冲区,然后才能读入它。一旦找到可以分配的值,您将达到
read
限制(在 Linux 和其他具有类似限制的系统上),除非您使用 GNUdd
并指定iflag=fullblock
:(
dd
复制不到 2 31个字节,即上面提到的 Linux 限制,甚至不到我要求的一半)。正如上面链接的问答中所解释的,
fullblock
在任何情况下,对于任何bs
大于 1 的值,您都需要可靠地复制所有输入数据。不管它的最大值是多少,那里都有一个更大的问题;来自 POSIX 规范:
(重点补充)
正如我过去写的,
dd
是一个非常愚蠢的工具:在你的情况下,它基本上归结为bs
只是dd
用于执行read(2)
系统调用的参数,但read(2)
允许执行“短读取”,即返回的字节数少于请求的字节数。事实上,如果它现在有一些可用的字节,它就是这样做的,即使它们不是你所要求的全部;如果输入文件是 tty、管道或套接字,这很典型(因此您的 CGI 尤其处于危险之中......)。试试看嘛:在这里我输入
asd
并按下回车;dd
读它(演奏一首read(STDIN_FILENO, buf, 1000)
并写出来;它read
按要求做了一个,所以它退出了。它看起来不像复制了 1000 个字节。归根结底,
dd
对于大多数需求来说,简单的“标准”是一种过于愚蠢的工具。您可以通过以下任一方式对其进行处理以执行您需要的操作:bs=1
和使用count
字节数;这可以保证复制您需要的字节数(如果在 EOF 之前可用),但效率很低,因为它每个字节执行一个系统调用;fullblock
标志;这确保dd
在写出之前累积一个完整的输入块。但是请注意,这是非标准的(GNU dd 有,IDK 有关于其他的)。最终,如果您要进行非 POSIX 扩展,我的建议是使用
head -c
: 它将做正确的事情,具有合理的缓冲并且没有特定的大小限制,确保正确性和良好的性能。最大值取决于系统(包括其分配策略)和当前可用的内存。
而不是一次尝试读取所有内容(您可能会耗尽内存,由于交换而减慢速度,您必须添加检查以查看它是否真的有效......)您可以使用
dd
.假设您想读取这些字节并将它们放入文件中。在 bash 中,你可以运行这样的东西(总字节数以 $total 为单位):