gpt4 book ai didi

bash - 为什么 "yes | sleep 10"管道不会失败

转载 作者:行者123 更新时间:2023-11-29 08:59:29 25 4
gpt4 key购买 nike

在考虑如何在我自己的一个程序中实现某个功能时,我一直想知道 bash 如何在内部处理以下性质的管道:

yes | sleep 10

这显然什么都不做,但我不明白这怎么不会导致错误。我本以为:

  • 因为 sleep 不从 stdin 读取,连接两个进程的管道将被填满并导致 yes 在尝试写入 now 时无限期阻塞满管

  • 如果使用非阻塞 IO,如果首先执行 yes 并在 sleep 进程运行之前写入管道,则应该发生错误,因此没有进程连接到管道的读取端

我想这是我的一些重大误解。我已经尝试查看 bash 源代码,但我无法理解。

最佳答案

这是运行 shell 命令时实际发生的事情 yes |睡 10

首先 shell 创建一个 anonymous pipe使用 pipe system call . pipe系统调用打开两个文件描述符,分别是管道的读端和写端。写入端的任何内容都可供读取端读取。

在此之后,shell 使用 fork system call 创建两个子进程.两个 child 并排跑。

  • 在一个 child 中,shell 将管道的写入端连接到标准输出并关闭读取端。然后 shell 调用 execve system callyes的代码图替换本过程中的代码图。
    程序 yes 会尽可能长时间地写入管道。如果管道的读取端没有事件的 read 调用,则 write 调用只会阻塞。 (实际上有一个小缓冲区,write 会在阻塞之前填满,但这在这里无关紧要。)
  • 在另一个 child 中,shell 将管道的读取端连接到标准输入并关闭写入端。然后shell调用execve系统调用将本进程中的代码镜像替换为sleep的代码镜像。sleep 程序在 10 秒内什么都不做。
  • 原始 shell 进程关闭管道的两端并等待其两个子进程退出(使用 wait system call)。

一旦 10 秒结束,运行 sleep 的进程就会退出。此时,管道的读端不再在任何进程中打开。当一个进程试图写入一个读端在任何进程中都没有打开的管道时,内核会发送一个SIGPIPE。向写入过程发出信号。因此,运行 yes 的进程被 SIGPIPE 信号杀死。

此时,shell 检测到它在管道两边的子进程已经退出。管道命令返回右侧的状态,即 0(sleep 成功退出)。

because sleep does not read from stdin, the pipe connecting both processes would fill up and cause yes to block indefinitely when it attempts to write to the now full pipe

这是正确的。

if non-blocking IO is used, errors should occur if yes is executed first and writes to the pipe before the sleep process is even run and thus no process is connected to the read end of the pipe

这在几个地方是不正确的。 yes 不使用非阻塞 IO。它与 sleep 并行执行,而不是首先执行。从来没有任何时间点没有进程连接到管道的读取端,直到 sleep 退出。根据时间的不同,yes 可能会在 sleep 开始执行之前开始写入,甚至可能在 sleep 程序的子进程被 fork 之前, 但当 pipe 调用返回时,读取端打开,同时写入端打开。

关于bash - 为什么 "yes | sleep 10"管道不会失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52456616/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com