为什么stdin和stdout看起来可以互换?

7
我知道stdin和stdout(至少在UNIX术语中)是流缓冲区,stdout用于从程序输出到控制台(或者被shell管道传输等),stdin用于程序标准输入。但是为什么在macOS上它们可以互换使用(stdout作为stdin,反之亦然)?
例如:
1. 如果你运行“cat /dev/stdin”,然后输入一些内容,它会回显出来。以“cat /dev/stdout”命令运行也是同样的结果。 2. 同样地,“echo“ Hey There”> /dev/stdout”和“echo“ Hey There”> /dev/stdin”都将“Hey There”输出回终端。 3. 它在C++中也可以工作:
#include <iostream>
#include <string>
#include <fstream>

int main(int argc, const char * argv[]) {
    std::string echoString;
    std::fstream stdoutFile;
    stdoutFile.open("/dev/stdout");
    stdoutFile << "Hey look! I'm using stdout properly!\nNow You trying using it wrongly: " << std::endl;
    stdoutFile >> echoString;
    stdoutFile << "You Typed: " << echoString << std::endl;
}

当提示输入时,只需输入单个单词,然后按下EOF (Ctrl+D),就可以按预期工作。


1
请注意,/dev/stdin/dev/stdout可以互换使用,并不意味着stdinstdout可以互换使用。特别是,如果您使用> /dev/stdin启动进程,则无法从该进程的标准输出流中读取数据。 - Brian Bi
@Brian 你是什么意思?这个似乎可以工作:http://pastebin.com/Su3yuJax - TheInnerParty
1
这与我说的不一样。std::fstream 默认以读/写模式打开。如果在终端上执行 > foo,它将以只写模式打开 foo,文件描述符将无法用于读取。 - Brian Bi
@Brian,我现在明白了。谢谢! - TheInnerParty
2个回答

4
因为通常情况下,当从交互式终端调用程序时,没有重定向,标准输入和标准输出都连接到同一个终端设备,例如/dev/tty(实际设备名称根据操作系统而异)。
终端设备是读/写设备。从终端设备读取将读取终端输入。向终端设备写入将在终端上生成输出。
您仍然有离散的文件描述符0和1,但它们连接到同一设备。
将其视为单向双向管道,它被复制到文件描述符0和1。
Linux的行为方式相同(您可以echo Foo >/dev/stdin并查看输出):
$ ls -al /proc/self/fd/[01]
lrwx------. 1 mrsam mrsam 64 Nov 22 21:34 /proc/self/fd/0 -> /dev/pts/1
lrwx------. 1 mrsam mrsam 64 Nov 22 21:34 /proc/self/fd/1 -> /dev/pts/1

所以,在这个过程中,文件描述符0和1都连接到/dev/pts/1,即相同的伪终端设备。无论您从文件描述符0还是文件描述符1读取,最终都将从相同的底层/dev设备读取,因此使用哪个实际文件描述符没有区别。
当然,这当然与操作系统有关。其他基于POSIX的操作系统可能会以其他方式实现标准输入和输出,因此您实际上无法写入标准输入并从标准输出中读取。

很好的/proc示例。 - sourcedelica

0

就像你所说,它们只是流缓冲区。它们没有强制执行特定的使用模式 - 只是惯例。作为编程便利,提供了标准输入流stdin、标准输出流stdout和标准错误流stderr。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接