Bash 如何通过管道传输大量数据?

Bash 如何通过管道传输大量数据?

假设你想抓取 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 可能会导致显示错误,因为内存中仅保留文件最近查看的部分;任何较早的数据都会丢失。

相关内容