我很困惑.在OSX和Linux下(使用BASH,TCSH,FISH和DASH),当直接通过终端提供输入时,此代码成功读取用户输入,而不是通过管道提供用户输入时.
更令人困惑的是:我不希望这些代码完全起作用!此代码是从STDOUT读取的.我希望读取调用返回错误,因为我实际上是从只写管道读取.
#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;
}
Run Code Online (Sandbox Code Playgroud)
要构建(假设您将示例命名为test.c):
$ gcc -o test test.c
Run Code Online (Sandbox Code Playgroud)
然后,这将读取用户输入:
$ ./test
abcd
I read 'abcd
'
Run Code Online (Sandbox Code Playgroud)
但是,这不是:
$ echo "abcd" | ./test
<< program still waiting for the read to finish
Run Code Online (Sandbox Code Playgroud)
任何见解?
终端将stdin和实现stdout为相同的读/写伪终端,并且默认情况下两个描述符都映射到同一事物。但是,当您使用管道时,shell 会创建一个具有不同读取和写入端的实际管道,其读取端会替换程序stdin的 ,但不会替换stdout. 因此,您无法从 读取管道的输入stdout,这不再与 相同stdin。
这是一个小测试,显示描述符会发生什么:
#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;
}
Run Code Online (Sandbox Code Playgroud)
运行时:
$ ./fdcheck
stdin dev=389931976 node=4338
stdout dev=389931976 node=4338
$ echo foo | ./fdcheck
stdin dev=0 node=-5077412903630272353
stdout dev=389931976 node=4338
Run Code Online (Sandbox Code Playgroud)
在 Linux 下你还可以这样做:
$ 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
Run Code Online (Sandbox Code Playgroud)