0

I have this:

$ 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

Question:

Why is the cat command line in the last line not dying prematurely with SIGPIPE? I think this should happen because grep terminates in no time compared to cat file that cats 183MB of file. With reading process gone cat will try to write to a broken pipe and should die with SIGPIPE.

Update:

I ended up writing this: 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);

}

I use it like this:

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

But still cat or yes does not die prematurely. I expect it to because by reading process is terminating before writing process is done writing.

Ankur Agarwal
  • 23,692
  • 41
  • 137
  • 208
  • `yes` is dying, otherwise it would stay for ever... – Basile Starynkevitch Sep 24 '13 at 05:14
  • 2
    As Basile Starynkevitch said, the `cat` and `yes` processes receive a `SIGPIPE` signal and get killed. The exit status of a pipeline is the exit status of the final command (i.e. `grep`), so if an earlier command fails, you won't see that in the exit status. What makes you think they're not dying prematurely? – Adam Rosenfield Sep 24 '13 at 05:44
  • @AdamRosenfield What makes you think they're not dying prematurely is the fact that I am not seeing an error message printed on the screen from `cat` or `yes` , they just silently exit. But that could be how they are implemented to handle SIGPIPE. – Ankur Agarwal Sep 24 '13 at 17:39
  • 1
    @abc: The default behavior of a `SIGPIPE` signal is to silently terminate the process. Try compiling and running a program that only does `main() { raise(SIGPIPE); }` -- it produces no output. – Adam Rosenfield Sep 24 '13 at 22:02

2 Answers2

2

If the read end of some pipe(2) is close(2)-ed, further write(2)s will get a SIGPIPE signal(7). Read also pipe(7).

They would get the SIGPIPE when the pipe buffer becomes full.

In the yes | ./readstdin command, the yes command gets a a SIGPIPE signal. Just try yes in a terminal, it spits some output indefinitely ad nauseam till you kill it.

In the cat file | ./readstdin command, it could happen (notably if file is quite small, less that sysconf(_POSIX_PIPE_BUF) bytes, which might be 4096 bytes), that the cat command is close(2)-ing the STDOUT_FILENO descriptor and that the pipe is still not full. Then cat may not get any SIGPIPE.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
1

Normal processes close the input stream causing a SIGPIPE. In the man page, it mentions that -m stops reading, and "ensures that standard input is positioned to just after the last matching line before exiting". So it doesn't actually close the stream. You can demonstrate like this:

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

You'll get the first c after the first z, which is sometimes useful. After the last grep exits, there is no place for the stream to go, so it's left unread and the whole group of commands exits. You can demonstrate:

(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
Ankur Agarwal
  • 23,692
  • 41
  • 137
  • 208
BraveNewCurrency
  • 12,654
  • 2
  • 42
  • 50