AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 436864
Accepted
user9303970
user9303970
Asked: 2018-04-11 13:05:24 +0800 CST2018-04-11 13:05:24 +0800 CST 2018-04-11 13:05:24 +0800 CST

FIFO(命名管道)与常规管道(未命名管道)有何不同?[复制]

  • 772
这个问题在这里已经有了答案:
使用 FIFO 与临时文件或管道的目的是什么? (1 个回答)
与未命名管道相比,使用命名管道有什么优势? (4 个回答)
4年前关闭。

FIFO(命名管道)与常规管道 (|) 有何不同?据我从Wikipedia了解到,与常规管道不同,FIFO 管道在流程结束后“继续存在”,并且可以在之后的某个时间删除。

cat x | grep y但是如果进程是基于一个包含管道(

此外,常规管道也具有它获得的第一个标准输出,作为另一个命令的标准输入,那么它不也是一种先进先出管道吗?

pipe fifo
  • 2 2 个回答
  • 9733 Views

2 个回答

  • Voted
  1. Best Answer
    derobert
    2018-04-11T15:11:22+08:002018-04-11T15:11:22+08:00

    “命名管道”实际上是一个非常准确的名称——它就像一个常规管道,除了它有一个名称(在文件系统上)。

    管道——使用的常规、未命名(“匿名”)some-command | grep pattern是一种特殊的文件。我的意思是文件,你读写它就像你对其他文件一样。Grep 并不真正关心¹它是从管道而不是终端³或普通文件中读取。

    从技术上讲,幕后发生的事情是 stdin、stdout 和 stderr 是传递给每个命令运行的三个打开文件(文件描述符)。文件描述符(在每个系统调用中用于读取/写入/等文件)只是数字;stdin、stdout 和 stderr 是文件描述符 0、1 和 2。因此,当您的 shell 设置some-command | grep它所做的事情时,如下所示:

    1. 向内核询问匿名管道。没有名称,因此对于普通文件无法使用openlike 来完成 - 而是使用pipeor完成pipe2,它返回两个文件描述符。⁴

    2. 分叉出一个子进程(fork()创建父进程的副本;管道的两端在此处打开),将管道的写入端复制到 fd 1(stdout)。内核有一个系统调用来复制文件描述符编号;它是dup2()或dup3()。然后它关闭读取端和写入端的其他副本。最后,它用于execve执行some-command. 由于管道是 fd 1,stdout ofsome-command是管道。

    3. 另一个子进程的分叉。这一次,它将管道的读取端复制到 fd 0 (stdin),并执行grep. 因此 grep 将从管道中读取为标准输入。

    4. 然后它等待这两个孩子退出。

    5. 此时,内核注意到管道不再打开,并且垃圾收集它。这就是真正破坏管道的原因。

    命名管道只是通过将匿名管道放入文件系统中来为其命名。所以现在任何open进程,在未来的任何时候,都可以通过使用普通的系统调用来获取管道的文件描述符。从概念上讲,管道不会被销毁,直到所有读取器/写入器都关闭它并且它是unlink从文件系统中编辑的。²

    顺便说一下,这就是文件在 Unix 上的一般工作方式。unlink(后面的系统调用rm)只是删除文件的名称之一;只有当所有名称都被删除并且没有任何文件打开时,它才会被实际删除。这里有几个答案探讨了这一点:

    • 为什么硬链接似乎与原始链接占用相同的空间?
    • 日志程序如何继续记录已删除的文件?
    • Linux 有什么不同之处,允许我删除/替换 Windows 会抱怨文件当前正在使用的文件?

    脚注

    1. 从技术上讲,这可能不是真的——通过了解可能会进行一些优化,并且实际的 grep 实现通常已经过大量优化。但从概念上讲,它并不关心(实际上 grep 的直接实现也不会)。
    2. 当然,内核实际上并没有将所有数据结构永远保存在内存中,而是在第一个程序打开命名管道时透明地重新创建它们(然后只要它打开就保持它们)。因此,就好像它们存在的时间一样长。
    3. 终端不是 grep 读取的常见位置,但当您不指定另一个标准输入时,它是默认的标准输入。因此,如果您只grep pattern在 shell 中输入,grep将从终端读取。想到的唯一用途是如果您要将某些内容粘贴到终端。
    4. 在 Linux 上,匿名管道实际上是在一个特殊的文件系统 pipefs 上创建的。有关详细信息,请参阅管道在 Linux中的工作原理。请注意,这是 Linux 的内部实现细节。
    • 23
  2. Peter Cordes
    2018-04-11T16:21:29+08:002018-04-11T16:21:29+08:00

    我认为您在管道的 shell 语法与底层 Unix 系统编程之间混淆了。管道 / FIFO 是一种不存储在磁盘上的文件,而是通过内核中的缓冲区将数据从写入器传递到读取器。

    管道/FIFO 的工作方式是相同的,无论写入器和读取器是通过系统调用(如open("/path/to/named_pipe", O_WRONLY);),还是使用 apipe(2)创建新的匿名管道并将打开的文件描述符返回给读取端和写入端。

    fstat(2)在管道文件描述符上会给你sb.st_mode & S_IFMT == S_IFIFO任何一种方式。


    当你运行foo | bar:

    • 对于任何非内置命令,shell 都会像平常一样分叉
    • 然后进行pipe(2)系统调用以获取两个文件描述符:匿名管道的输入和输出。
    • 然后它再次分叉。
    • 孩子(fork()返回 0)
      • 关闭管道的读取端(保持写入 fd 打开)
      • 并重定向stdout到 write fddup2(pipefd[1], 1)
      • 然后确实execve("/usr/bin/foo", ...)
    • 父级(fork()返回非 0 子 PID)
      • 关闭管道的写入端(保持读取 fd 打开)
      • stdin并从读取的 fd重定向dup2(pipefd[0], 0)
      • 然后确实execve("/usr/bin/bar", ...)

    如果你跑步,你会遇到非常相似的情况foo > named_pipe & bar < named_pipe。

    命名管道是进程在彼此之间建立管道的集合点。


    这种情况类似于匿名 tmp 文件与具有名称的文件。您可以open("/path/to/dir", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);创建一个没有名称( O_TMPFILE) 的临时文件,就像您打开"/path/to/dir/tmpfile"然后O_CREAT取消链接它一样,为您留下一个已删除文件的文件描述符。

    使用linkat,您甚至可以将该匿名文件链接到文件系统,并为其命名,如果它是用O_TMPFILE. (但是,对于使用名称创建然后删除的文件,您不能在 Linux 上执行此操作。)

    • 4

相关问题

  • 如何在 bash 中使用“sudo”调用时将“yes”或“y”通过管道传输到程序中?

  • 将句柄传递给标准输入下行管道

  • 如何通过管道传输 bash 命令并保持 Ctrl+C 正常工作?

  • 为什么管道`mysql`到'tail'会改变输出格式?

  • `tee` 和 `bash` 进程替换顺序

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve