Why can I read from STDOUT and get a user's terminal input?
c, linux
Solution
The terminal implements `stdin` and `stdout` as the same read/write pseudo terminal and the two descriptors both map to the same thing by default. However, when you use a pipe the shell creates an actual pipe with distinct read and write ends, the read-end of which replaces the `stdin` of your program but not the `stdout`. Thus you cannot read the pipe's input from `stdout`, which is no longer the same thing as `stdin`.
Here's a little test showing what happens to the descriptors:
#include <stdio.h>
#include <sys/stat.h>
int main (void) {
struct stat st;
(void) fstat(0, &st);
(void) printf("stdin dev=%ld node=%ld\n", (long) st.st_dev, (long) st.st_ino);
(void) fstat(1, &st);
(void) printf("stdout dev=%ld node=%ld\n", (long) st.st_dev, (long) st.st_ino);
return 0;
}
And when run:
$ ./fdcheck
stdin dev=389931976 node=4338
stdout dev=389931976 node=4338
$ echo foo | ./fdcheck
stdin dev=0 node=-5077412903630272353
stdout dev=389931976 node=4338
Under Linux you can also do:
$ readlink /proc/self/fd/0
/dev/pts/4
$ echo foo | readlink /proc/self/fd/0
pipe:[353335]
$ echo foo | readlink /proc/self/fd/1
/dev/pts/4
Problem
I'm perplexed. Under OSX and Linux (using BASH, TCSH, FISH, and DASH) this code successfully reads user input when that input is provided directly through the terminal but not when the user input is provided through a pipe. Even more perplexing though: I don't expect this code to work at all! This code is READING from STDOUT. I'd expect the read call to return an error since I'm essentially reading from a write only pipe. ``` #include <unistd.h> #include <stdio.h> int main(int argc, char** argv) { char buffer[11]; size_t nread; if((nread=read(1, buffer, sizeof(buffer)-1)) <= 0) { fprintf(stderr, "error!\n"); return 1; } buffer[nread] = '\0'; printf("I read '%s'\n", buffer); return 0; } ``` To build (assuming you named the sample test.c): ``` $ gcc -o test test.c ``` Then, this reads the user input: ``` $ ./test abcd I read 'abcd ' ``` But, this does not: ``` $ echo "abcd" | ./test << program still waiting for the read to finish ``` Any insights?