读取过程中的Unix / Linux管道行为在写入过程之前终止

时间:2013-09-24 03:22:28

标签: c linux pipe

我有这个:

$ 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死亡?我认为这应该发生,因为grep与猫{183}文件的cat file相比没有时间终止。随着读取过程消失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不会过早死亡。我期待它,因为通过阅读过程在写作过程完成之前终止。

2 个答案:

答案 0 :(得分:2)

如果某些pipe(2)的阅读结尾为close(2),则write(2)将获得SIGPIPE signal(7)。另请阅读pipe(7)

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

yes | ./readstdin命令中,yes命令获得一个SIGPIPE信号。只需在终端中尝试yes,它就会无限期地输出输出 ,直到你杀死它为止。

cat file | ./readstdin命令中,可能会发生(file非常小,少于sysconf(_POSIX_PIPE_BUF)字节,可能是4096字节)cat命令是close(2) - STDOUT_FILENO描述符,并且管道仍未满。然后cat可能无法获得任何SIGPIPE

答案 1 :(得分:1)

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

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

您将在第一个c之后获得第一个z,这有时很有用。在最后一个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