【问题标题】:Unix/Linux pipe behavior when reading process terminates before writing process读取进程在写入进程之前终止时的 Unix/Linux 管道行为
【发布时间】:2013-09-24 03:22:27
【问题描述】:

我有这个:

$ ls -lh file
-rw-r--r-- 1 ankur root 181M Sep 23 20:09 file

$ head -6 file

z
abc
abc
abc
abc
abc

$ cat file | grep -m 1 z
z

问题:

为什么最后一行的cat 命令行不会因 SIGPIPE 而过早死亡?我认为这应该发生,因为与 cat file 相比,grep 立即终止了 183MB 的文件。随着阅读过程的结束cat 将尝试写入损坏的管道,并且应该与 SIGPIPE 一起死。

更新:

我最终写了这个:readstdin.c

# include <unistd.h>
# include <stdio.h>

int main() {

    ssize_t n ;        
    char a[5];        
    n = read(0, a, 3);
    printf("read %zd bytes\n", n);
    return(0);

}

我是这样使用的:

$ cat file | ./readstdin
$ yes | ./readstdin

catyes 仍然不会过早死亡。我希望它会这样,因为通过读取过程在写入过程完成写入之前终止。

【问题讨论】:

  • yes 正在死去,否则它将永远存在......
  • 正如 Basile Starynkevitch 所说,catyes 进程收到 SIGPIPE 信号并被杀死。管道的退出状态是最终命令的退出状态(即grep),因此如果较早的命令失败,您将不会在退出状态中看到它。是什么让您认为他们不会过早死亡?
  • @AdamRosenfield 让你认为他们不会过早死亡的事实是,我没有看到屏幕上打印出来自catyes 的错误消息,他们只是默默地退出。但这可能是它们被实施以处理 SIGPIPE 的方式。
  • @abc:SIGPIPE 信号的默认行为是静默终止进程。尝试编译并运行一个只执行main() { raise(SIGPIPE); } 的程序——它不会产生任何输出。

标签: c linux pipe


【解决方案1】:

如果某些pipe(2) 的读取结束是close(2)-ed,则进一步的write(2)s 将得到SIGPIPE signal(7)。另请阅读pipe(7)

当管道缓冲区满时,他们会得到SIGPIPE

yes | ./readstdin 命令中,yes 命令得到一个SIGPIPE 信号。只需在终端中尝试yes,它会吐出一些输出无限地令人作呕,直到你杀死它。

cat file | ./readstdin 命令中,它可能发生(特别是如果file 非常小,小于sysconf(_POSIX_PIPE_BUF) 字节,可能是4096 字节),cat 命令是close(2)-ing STDOUT_FILENO 描述符并且管道仍未满。那么cat 可能得不到任何SIGPIPE

【讨论】:

  • 请查看我对问题的更新。任何见解将不胜感激。
【解决方案2】:

正常进程关闭导致 SIGPIPE 的输入流。在手册页中,它提到-m 停止读取,并“确保标准输入位于退出前的最后一个匹配行之后”。所以它实际上并没有关闭流。你可以这样演示:

cat file | (grep -m1 z && grep -m1 c)

您将在第一个 z 之后获得第一个 c,这有时很有用。在最后一个 grep 退出后,流没有地方可去,所以它处于未读状态,整个命令组都退出。你可以演示一下:

(while true; do echo z; sleep 1; done) | grep -m3 z
(while true; do echo z; sleep 1; done) | grep --line-buffered z | head -3

【讨论】:

  • 如果读取过程在写入过程完成之前终止(或完成)怎么办?在那种情况下会发生什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-15
  • 1970-01-01
相关资源
最近更新 更多