根据希利的这个回答,less
如果无法打开,则从 stderr 读取导航命令/dev/tty
。
这似乎令人费解,因为我从未见过任何东西写入另一个程序的 stderr 流,而且我不知道如何实现这一点。
stderr 开放读写的目的是什么?如果这有用,我如何在现代系统上使用它? (例如,是否有一些神秘的语法可以将某些内容通过管道传输到 stderr 而不是 stdin ?)
答案1
一开始我很惊讶。然而,在阅读了答案并做了一些调查后,这似乎很简单。这就是我发现的。 (最后没有什么意外。)
在重定向之前,stdin、stdout 和 stderr 按预期连接到同一设备。
#ctrl-alt-delor:~$
#↳ ll /dev/std*
lrwxrwxrwx 1 root root 15 Jun 3 20:58 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Jun 3 20:58 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Jun 3 20:58 /dev/stdout -> /proc/self/fd/1
#ctrl-alt-delor:~$
#↳ ll /proc/self/fd/*
lrwx------ 1 richard richard 64 Jun 30 19:14 /proc/self/fd/0 -> /dev/pts/12
lrwx------ 1 richard richard 64 Jun 30 19:14 /proc/self/fd/1 -> /dev/pts/12
lrwx------ 1 richard richard 64 Jun 30 19:14 /proc/self/fd/2 -> /dev/pts/12
因此,大多数重定向(即 stderr)之后不会被重定向。 stderr 仍然连接到终端。因此可以读取它,以获得键盘输入。
唯一阻止文件以意外方向使用的因素是约定,并且管道是单向的。
另一个例子,尝试:
cat | less
当尝试读取终端时,在翻页后会出现错误less
(这并不奇怪,cat
读取终端也是如此)。
/dev/tty
更神秘的是,它不是链接进去的/proc/self
。
#ctrl-alt-delor:~$
#↳ ll /dev/tty
crw-rw-rw- 1 root tty 5, 0 Jun 29 09:18 /dev/tty
看我当前的控制终端和`/dev/tty`之间有什么关系?进行解释。感谢@StephenKitt 提供的链接。
答案2
dup(2)
当您登录时,stdin、stdout 和 stderr 将连接到您登录的终端。更准确地说,tty 通常会打开,stdout 和 stderr 是对第一个文件描述符进行两次操作的结果。这允许从 stderr 读取以便从终端获取输入。
正如另一个答案中提到的,程序读来自 stderr 以获得问题的交互式答复。
由于用户无法知道程序在什么情况下从 stderr 读取数据,因此故意从另一个程序向 stderr 写入数据是无用的尝试。
请注意,今天的程序通常首先尝试打开/dev/tty
并使用 stderr,仅在不起作用的情况下。
仅从 stderr 读取的程序通常自 1979 年以来从未被修改过,此类程序通常包含如下结构:
int i 1;
或者
i =* 2;
现代 C 编译器不接受。因此,您今天不太可能找到一个永远不会打开/dev/tty
而是读取来自 stderr 的交互式回复的程序。