为什么 stdin 和 stdout 看起来可以互换?
Why are stdin and stdout seemingly interchangeable?
我知道 stdin 和 stdout(至少在 UNIX 中是这样)是流缓冲区,而 stdout 用于从程序输出到控制台(或者由 shell 等进行管道传输) ), 而 stdin 是程序的标准输入..
那么,至少在 macOS 上,为什么它们可以互换使用(标准输出作为标准输入,反之亦然?
示例:
如果你 运行 cat /dev/stdin
然后输入一些东西,它会回显。 运行 与 cat /dev/stdout
相同的命令。
类似地,echo "Hey There" > /dev/stdout
和echo "Hey There" > /dev/stdin
都将'Hey There'输出回终端。
它也适用于 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) 即可正常工作。
因为,通常情况下,当从交互式终端调用程序时,没有重定向,标准输入和标准输出都连接到同一终端设备,例如/dev/tty
(实际设备名称不同基于操作系统)。
终端设备是read/write设备。从终端设备读取读取终端输入。写入终端设备会在终端上生成输出。
您仍然有离散的文件描述符 0 和 1,但它们连接到同一设备。
将其视为单个双向管道,dup
同时连接到文件描述符 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 的操作系统可能会以其他方式实现其标准输入和输出,您实际上无法写入标准输入并从标准输出读取。
如您所说,它们只是流缓冲区。它们并没有强制执行特定的使用模式——只是约定俗成。流缓冲区 stdin、stdout 和 stderr 都是为了方便编程而提供的。
我知道 stdin 和 stdout(至少在 UNIX 中是这样)是流缓冲区,而 stdout 用于从程序输出到控制台(或者由 shell 等进行管道传输) ), 而 stdin 是程序的标准输入..
那么,至少在 macOS 上,为什么它们可以互换使用(标准输出作为标准输入,反之亦然?
示例:
如果你 运行
cat /dev/stdin
然后输入一些东西,它会回显。 运行 与cat /dev/stdout
相同的命令。类似地,
echo "Hey There" > /dev/stdout
和echo "Hey There" > /dev/stdin
都将'Hey There'输出回终端。它也适用于 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) 即可正常工作。
因为,通常情况下,当从交互式终端调用程序时,没有重定向,标准输入和标准输出都连接到同一终端设备,例如/dev/tty
(实际设备名称不同基于操作系统)。
终端设备是read/write设备。从终端设备读取读取终端输入。写入终端设备会在终端上生成输出。
您仍然有离散的文件描述符 0 和 1,但它们连接到同一设备。
将其视为单个双向管道,dup
同时连接到文件描述符 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 的操作系统可能会以其他方式实现其标准输入和输出,您实际上无法写入标准输入并从标准输出读取。
如您所说,它们只是流缓冲区。它们并没有强制执行特定的使用模式——只是约定俗成。流缓冲区 stdin、stdout 和 stderr 都是为了方便编程而提供的。