Reputation: 24768
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.
Upvotes: 0
Views: 1996
Reputation: 1
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
.
Upvotes: 2
Reputation: 13065
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
Upvotes: 1