我将1
(stdout)/ 2
(stderr) 传递给read
系统调用,但它仍然可以正常工作。然后我将0
(stdin) 传递给write
系统调用并发现它也有效!
int main(int argc, char** argv){
char buf[1024] = "abcdefghi\n";
write(0, buf, 10);
char readbuf[1024] = {0};
// read(1, readbuf, 10); works too
read(2, readbuf, 10);
write(2, readbuf, 10);
return 0;
}
输出:
abcdefghi
hey stdin <-- I input this
hey stdin
很迷茫,我以为应该是错误。
实验:
然后我尝试重定向 fd 2。
$ ./a.out 2>/dev/null
这次读取和第二次写入都不是“可见的”。输出是
abcdefgi
那么stderr可以用于读取吗?
然后我关闭标准输出和标准错误并制作两个标准输入副本:
int main(int argc, char** argv){
char buf[1024] = "abcdefghi\n";
close(1);
close(2);
dup2(0, 1);
dup2(0, 2);
write(0, buf, 10);
char redbuf[1024] = {0};
read(2, redbuf, 10);
write(2, redbuf, 10);
return 0;
}
它再次起作用。
输出:
abcdefghi
hey stdin <-- I input this
hey stdin
那么stdin可以用来写吗?
我在这里需要一些解释。
问题
我想知道:
为什么 stdout/stderr 可以用于读取?
为什么stdin可以用于写?
三个流(stdin,stdout,stderr)在内部是一个流吗?
如果不是,为什么我会得到这个结果?
仅将 fd 0/1/2 用于输入/输出/错误是惯例。如果您在没有重定向的情况下调用程序,则所有三个都指向您的 tty,并且您的 tty 是打开的,具有读写访问权限。这意味着您可以根据需要读取或写入它们。您可以将它们称为相同的流,尽管表达式流通常用于更高级别的 I/O,例如
FILE
在 C 或stream
C++ 中。这就是为什么两个或不重定向的示例都只是回显您输入的文本的原因。
另一方面,如果您进行重定向,shell 将以只读或只写访问权限打开文件。在您的示例
./a.out 2>/dev/null
中,写入0
仍然连接到终端,因为它没有被重定向,因此显示在屏幕上。读取2
连接到只写/dev/null
,因此应该失败,但您不会注意到与您的程序的区别。写入2
成功,但写入/dev/null
. 无效读取和有效写入/dev/null
在您的终端上不可见。只要您没有重定向 stdin/stdout/stderr,这些文件描述符就已由登录过程打开,并打开相关
tty
的读写作为第一个文件(导致文件描述符 #0),然后调用dup()
2 次以获取stdout 和 stderr 的文件描述符。正如`less` 如何从标准输入中获取数据同时仍然能够从用户读取命令中所述?以前(之前
/dev/tty
已经介绍过UNIX
)程序,例如在要求确认时more
读取的。stderr