假设你想抓取 a 的内容真的很大文件,但想一次查看它的几个部分。假设要执行以下操作:
$ cat /dev/sda1 | less
作为 Java 和 ActionScript 等语言的程序员,当我查看该代码时,我想象 Bash 首先运行命令cat /dev/sda1
(加载一切命令返回到 RAM 中),然后运行less
可以访问表示为 的真正大“伪变量”的命令-
。
这就是 Bash 做事的方式吗(意味着命令是一个特别糟糕想法如果文件大于系统上的 RAM 量,您应该使用另一个命令),或者它是否有一种优化大量数据管道的方法?
答案1
不,它不会将所有内容加载到内存中,这是一种不切实际的设计方式。它使用缓冲区来缓冲管道左侧的输出,然后将这些缓冲区连接到管道右侧命令的输入。
手册页man 7 pipe
包含所有详细信息,以及其他 U&L 问答,标题为:管道缓冲区有多大?
答案2
读取将阻塞直到数据可用,而写入将在管道已满时阻塞或失败。参数很少,例如管道缓冲区,管道大小和O_非阻塞在管道中起着关键作用。
PIPE_BUF 的值可以通过 'ulimit -a' 确定。它在limits.h 中定义。 PIPE_BUF 控制保证大小原子写。这有助于制作安全的多线程应用程序。
PIPE_SIZE 取决于页面大小。在2.4内核中,相当于一页的大小(4KB)。然而2.6之后的版本被映射到16页(64KB)的数组。这在文件 pipeline_fs_i.h 中定义为 PIPE_BUFFERS (16)。更高版本的内核具有 fcntl 和 F_SETPIPE_SZ ,可以增加页面大小。
O_NONBLOCK 允许执行部分写入和延迟写入。但是,如果启用了 O_NONBLOCK,但如果要写入管道中的字节数大于 PIPE_BUF,则在管道已满的情况下写入将失败,否则根据写入的返回值,它将与来自其他进程的数据交错。
答案3
尝试使用 option -B
,它仅使用 64k 缓冲区。
cat /dev/sda1 | less -B
从man less
:
-B 或 --auto-buffers 默认情况下,当从管道读取数据时,会根据需要自动分配缓冲区。如果从管道读取大量数据,可能会导致分配大量内存。 -B 选项禁用管道缓冲区的自动分配,因此管道仅使用 64K(或 -b 选项指定的空间量)。警告:使用 -B 可能会导致显示错误,因为内存中仅保留文件最近查看的部分;任何较早的数据都会丢失。