如何理解管道


21

当我只是在bash中使用管道时,我对此并没有多加考虑。但是,当我使用系统调用pipe()和fork()一起阅读一些C代码示例时,我不知道如何理解管道,包括匿名管道和命名管道。

经常听到“ Linux / Unix中的所有内容都是文件”。我想知道管道实际上是否是文件,以便它连接的一部分写入管道文件,而另一部分从管道文件读取吗?如果是,在哪里创建匿名管道的管道文件?在/ tmp,/ dev或...?

但是,从命名管道的示例中,我还了解到,使用管道比显式使用临时文件具有空间和时间性能上的优势,这可能是因为管道的实现中没有涉及文件。同样,管道似乎不像文件那样存储数据。所以我怀疑管道实际上是一个文件。

Answers:


23

关于性能问题,管道比文件更有效,因为不需要磁盘IO。因此,cmd1 | cmd2它的效率比cmd1 > tmpfile; cmd2 < tmpfile(如果tmpfile以命名管道的形式备份在RAM磁盘或其他存储设备上,则可能不正确;但是如果是命名管道,cmd1则应在后台运行,因为如果管道已满,其输出可能会阻塞)。如果您需要结果cmd1并将其输出发送到cmd2,则应cmd1 | tee tmpfile | cmd2允许cmd1cmd2并行运行,避免从进行磁盘读取操作cmd2

如果许多进程读/写同一管道,则命名管道很有用。当程序未设计为将stdin / stdout用于需要使用文件的 IO时,它们也很有用。我将文件用斜体表示,因为命名管道不是驻留在内存中的文件,因为它们驻留在内存中并且具有固定的缓冲区大小,即使它们具有文件系统条目(仅供参考)。其他的事情在UNIX文件系统有没有条目被文件:只是觉得/dev/null,还是别人的条目/dev/proc

由于管道(命名管道和未命名管道)具有固定的缓冲区大小,因此它们的读取/写入操作可能会阻塞,从而导致读取/写入过程进入IOWait状态。另外,从存储缓冲区读取时何时收到EOF?有关此行为的规则定义明确,可以在该人员中找到。

您无法使用管道(命名管道和未命名管道)做的一件事是在数据中查找。由于它们是使用内存缓冲区实现的,因此这是可以理解的。

关于"everything in Linux/Unix is a file",我不同意。命名管道具有文件系统条目,但不完全是文件。未命名的管道没有文件系统条目(可能在中除外/proc)。但是,在UNIX上,大多数IO操作都是使用读/写功能完成的,该功能需要文件描述符,包括未命名的管道(和套接字)。我认为我们不能这么说"everything in Linux/Unix is a file",但是我们可以肯定地说"most IO in Linux/Unix is done using a file descriptor"


谢谢!这两个命令是否通过并行运行的管道连接,而不是第二个命令在第一个命令完成后开始运行?
蒂姆(Tim)

是的,这两个命令是并行运行的。如果它们不是,并且第一个输出大于缓冲区,它将被阻塞。您可以通过在2个不同的shell中运行cmd1 > fifo并使用cmd2 < fifo来创建命名管道,以进行尝试mkfifo fifo
jfg956

您可以执行的另一项测试是cmd2cmd1仍在运行时杀死它:cmd1可能会停止报告损坏的管道消息。
jfg956

谢谢!你是什​​么意思会被阻止?如果发生这种情况,是否意味着区块后的流中的日期将丢失?
蒂姆(Tim)

2
数据不会丢失。如果管道缓冲区已满,cmd1则只有在cmd2从管道中读取数据后,才会返回对管道的写入。以相同的方式,cmd2如果缓冲区为空,则从管道读取会阻塞,直到cmd1写入管道为止。
jfg956

4

UNIX哲学的两个基本基础是

  1. 制作能做一件事的小型程序。
  2. 并期望每个程序的输出都将成为另一个程序的输入,
    而这个程序仍然是未知的。

    管道的使用使您可以利用这两个设计
    基础的效果来创建功能强大的命令链,以实现所需的结果。

    大多数对文件进行操作的命令行程序也可以接受标准输入(通过键盘输入)上的输入,并输出到标准输出(在
    屏幕上打印)。

    有些命令仅在管道中运行,不能直接在文件中运行。

    例如tr命令

  ls -C | tr 'a-z' 'A-Z'
    cmd1 | cmd2
  • 将cmd1的STDOUT发送到cmd2的STDIN而不是屏幕。

  • STDERR不会跨管道转发。

    总之Pipes is character (|)可以连接命令。

    写入STDOUT的任何命令都可以在管道的左侧使用。

       ls - /etc | less 

    从STDIN读取的任何命令都可以在管道的右侧使用。

       echo "test print" | lpr 

    传统管道被称为“未命名”,因为它匿名存在,并且仅在进程运行时才持久存在。命名管道是系统持久性的,并且存在于过程的生命周期之外,一旦不再使用,必须将其删除。进程通常附加到命名管道(通常显示为文件)以执行进程间通信(IPC)。

来源:http : //en.wikipedia.org/wiki/Named_pipe


3

为了补充其他答案...

stdin和stdout是文件描述符,就像文件一样被读写。因此,您可以这样做echo hi | grep hi,它将用管道替换echo的stdout并将grep的stdin替换到该管道的另一端。


1

一切都是文件。

如果我们从字面上看这句话,那么最终的含义是“我们只有文件,没有别的”。这不是正确的解释,那是什么。

当我们说“一切都是文件”时,并不是说一切都存储在磁盘上。我们说的一切看起来都像文件,可以读取,可以写入。

在Unix中,一旦打开文件或非文件,则可以将其视为文件。但是,并非所有文件都支持所有操作。例如,某些文件(不是文件)不支持搜索:它们必须按顺序读取/写入(对于管道和套接字,这是正确的)。

一切都有文件名(在某些系统上:例如Debian Gnu / Linux和许多其他Gnu / Linux)。

  • 所有打开的文件都获得一个文件名。看到/proc/self/fd/…
  • 可以使用文件名打开网络套接字,/dev/tcp
    例如cat </dev/tcp/towel.blinkenlights.nl/23

最后一部分仅在具有/proc文件系统的系统和提供/dev/tcp文件结构的系统(或外壳)上有效。
库萨兰达
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.