UNIX 中管道机制如何工作

问题描述 投票:0回答:1

我想确认一下我对 UNIX 命令执行中管道的理解。

当我们在一系列命令中使用管道时,前面命令的输出将作为输入传递给后面的命令。

众所周知,UNIX 中的一切都是文件。而且每个进程(又名:命令)都有自己的

STDIN
STDOUT
专用文件。我们可以回忆一下,这些并不直接链接到终端。

让我们考虑下面的例子:

假设 abc.txt 是工作目录中存在的文件。

cat abc.txt | cat

上面,第一个命令

cat abc.txt
将输出(文件 abc.txt 的内容)写入其专用标准输出文件(
/proc/<processID>/fd/1
否则
STDOUT
)。 下一个
cat
命令假设从其自己的标准输入文件中读取(
/proc/<processID>/fd/0
,否则
STDIN
)。

第一个 cat 命令中的

STDOUT
文件与第二个 cat 命令中的
STDIN
文件完全不同。这两个 cat 命令是不同的进程,因此会有所不同。因此就有了 STDIN 和 STDOUT 文件。

我的理解是:

UNIX操作系统(当遇到管道机制时),要么将前面命令的STDOUT文件的内容复制到后面命令的STDIN文件中,要么 将前一个命令的 STDOUT 文件对后一个命令的 STDIN 文件进行符号引用。

我这里说得对吗?

提前致谢。

unix pipe
1个回答
0
投票

你说得完全正确!对于那些对血腥细节感到好奇的人......

每个进程内部都有一个指向存储在内核内存中的文件结构的指针数组。当程序最终调用文件打开、关闭等系统调用时,这些文件结构将在内核内存中分配和释放,并且指向它们的指针存储在进程的文件数组中。存储在进程中的该数组的索引只不过是文件描述符。因此,当您向系统调用传递文件描述符时,操作系统能够查找引用相关进程的文件。

通常索引 0、1 和 2 按惯例保留,我们将它们称为 STDIN、STDOUT 和 STDERR,但请记住它们只是包含指向打开“文件”的指针的数组的索引。还需要注意的是,管道系统调用预留了两个文件描述符,一个用于文件的“读”端,一个用于文件的“写”端。有问题的实际文件不是磁盘上的东西,而是在内核中预留的一块内存(当您调用管道系统调用时),可以使用“write”文件描述符上的 write 系统调用进行写入并使用“读取”文件描述符上的读取系统调用进行读取。

现在,让你的 shell 程序运行这样的链式命令的魔力涉及到分叉、执行、文件关闭和管道系统调用的复杂安排。最终,链中的每个进程都将其 1 个文件描述符 (STDOUT) 设置为管道的写入端,并将 0 个文件描述符 (STDIN) 设置为管道的读取端。这会在两个进程之间创建一条链,以便它们可以从内存中的共享空间进行读写。链中的起始命令和结束命令最终定义了初始数据的来源以及最终数据的写入位置。

使用上面的示例,假设我们有两个进程,进程 A 是运行 cat abc.txt 的程序,进程 B 是运行 cat 的程序。您的 shell 程序将设置进程,以便:

进程A:fd 0被设置为abc.txt文件,fd 1是内存中共享管道的写入端。 进程B:fd 0是内存中共享管道的读取端,fd 1被设置为终端(这通常是因为这是STDOUT在不被覆盖时默认的设置)。

以这种方式定义事物的巧妙之处在于,cat 程序实际上不知道它在哪里读取或写入内容,除了在 fd 0 处读取文件并写入 fd 1 之外。以这种方式设置文件描述符意味着您的第一只猫将读取 abc.txt 文件,并将其写入共享管道内存,第二只猫将从该共享管道内存读取文件内容,并将其写入终端。

事情变得有点复杂,因为读取和写入通常发生在块中,这在使用文件读取和文件写入系统调用时很常见,但这对于问题来说并不重要。

© www.soinside.com 2019 - 2024. All rights reserved.