This question is a follow-up of 'Why does select() say that stdout and stderr are ready for reading and stdin is ready for writing?' which got closed as a duplicate of 'Writing to stdin and reading from stdout (UNIX/LINUX/C Programming)'.
While that question explains why we can read from file descriptors meant for stdout and stderr, the current question is different. This question is concerned about why stdout and stderr are ready for reading in a program while entering input manually from terminal but not so while redirecting standard input to the program.
Here is the code to reproduce the behavior. The following program attempts to check if stdin, stdout and stderr is ready for reading.
#include <stdio.h>
#include <sys/select.h>
int main(void)
{
struct timeval tv;
fd_set fds;
int fd;
tv.tv_sec = 10;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(0, &fds);
FD_SET(1, &fds);
FD_SET(2, &fds);
select(3, &fds, NULL, NULL, &tv);
for (fd = 0; fd < 3; fd++) {
if (FD_ISSET(fd, &fds)) {
printf("fd %d ready\n", fd);
}
}
printf("tv: %ld seconds %ld microseconds\n", tv.tv_sec, tv.tv_usec);
return 0;
}
If I wait for about 2 seconds and enter some data in standard input, the select()
call returns and this is the output.
$ gcc readselect.c && ./a.out
hi
fd 0 ready
fd 1 ready
fd 2 ready
tv: 8 seconds 222132 microseconds
However, if I redirect standard input to my program, then the program shows that only stdin is ready for reading.
$ gcc readselect.c && (sleep 2; echo hi) | ./a.out
fd 0 ready
tv: 7 seconds 994713 microseconds
Why does the behavior change now? Why does the program no longer say that stdout and stderr are also ready for reading like it did in the earlier example?