理解 Unix/Linux 中的管道命令

nih*_*lus 16 pipe terminology

我有两个简单的程序:AB.? A将首先运行,然后B获取“stdout”A并将其用作“stdin”。?假设我使用的是 GNU/Linux 操作系统,最简单的方法是:

./A | ./B
Run Code Online (Sandbox Code Playgroud)

如果我必须描述这个命令,我会说它是一个从生产者 ( A)获取输入(即读取)并写入消费者 ( B) 的命令。?这是一个正确的描述吗?我错过了什么吗?

Kus*_*nda 27

关于你的问题,唯一错误的是你说

A 将首先运行,然后 B 获得 A 的标准输出

事实上,这两个程序几乎同时启动。如果B它尝试读取时没有输入,它将阻塞,直到有输入读取。同样,如果没有人从 读取输出A,它的写入将阻塞,直到它的输出被读取(其中一些将被管道缓冲)。

唯一同步参与管道的进程是 I/O,即跨管道的读取和写入。如果没有写入或读取发生,那么这两个进程将完全独立运行。如果一个进程忽略另一个进程的读取或写入,则被忽略的进程将阻塞并最终被SIGPIPE信号(如果写入)杀死,或者在另一个进程终止时在其标准输入流(如果读取)上获得文件结束条件.

惯用的描述方式A | B是它是一个包含两个程序的管道。在第一个程序的标准输出上产生的输出可以在第二个程序的标准输入上读取(“[输出]A被管道传输到 [输入] B”)。外壳执行所需的管道以允许这种情况发生。

如果你想用“消费者”和“生产者”这两个词,我想也可以。

这些是用 C 编写的程序这一事实与此无关。这与 Linux、macOS、OpenBSD 或 AIX 无关。

  • @AlexVong 不,那是 * 完全 * 偏离轨道。这甚至无法解释像`yes | 这样简单的事情。sed 10q` (6认同)
  • @AlexVong 那篇文章中所做的简化使其与实际管道分离;并行执行是真正的语义,而不是优化。对于看过 shell 管道的人来说,这是对孩子的合理谎言解释 * 单子评估 * 或组合,但在另一个方向上是无效的。Kusalananda 的 fifo 版本更接近,但模型的错误传播部分非常重要且不可复制。(所有这些都是我作为一个非常喜欢“shell 管道只是函数组合”的人说的) (3认同)
  • 在 DOS 中使用写入临时文件,因为它不支持多个进程。 (2认同)
  • @AlexVong 请注意,尽管您的带有临时文件的示例并不完全等效。程序可能会选择查找文件的内容,但无法查找来自管道的数据。一个更好的例子是使用 `mkfifo` 创建一个命名管道,然后在后台启动 B 从管道读取,然后 A 写入它。不过,这是吹毛求疵,因为 _effect_ 是一样的。 (2认同)