Less 从 stderr 获取键盘输入?
我正在查看“less”实用程序的代码,特别是它如何获取键盘输入。有趣的是,在 ttyin.c 的第 80 行,它设置了要读取的文件描述符:
/*
* Try /dev/tty.
* If that doesn't work, use file descriptor 2,
* which in Unix is usually attached to the screen,
* but also usually lets you read from the keyboard.
*/
#if OS2
/* The __open() system call translates "/dev/tty" to "con". */
tty = __open("/dev/tty", OPEN_READ);
#else
tty = open("/dev/tty", OPEN_READ);
#endif
if (tty < 0)
tty = 2;
难道文件描述符 2 不是 stderr?如果是这样,那是什么呢?我认为键盘输入是通过标准输入发送的。
有趣的是,即使您执行 ls -l * | less,文件加载完成后,你仍然可以使用键盘上下滚动,但如果你执行ls -l * | vi
,那么 vi 就会对你大喊大叫,因为它不从 stdin 读取数据。有什么大创意?我怎么会来到这个奇怪的新领域,其中 stderr 既是向屏幕报告错误又是从键盘读取错误的方式?我想我已经不在堪萨斯了...
I'm taking a look at the code to the 'less' utility, specifically how it gets keyboard input. Interestingly, on line 80 of ttyin.c, it sets the file descriptor to read from:
/*
* Try /dev/tty.
* If that doesn't work, use file descriptor 2,
* which in Unix is usually attached to the screen,
* but also usually lets you read from the keyboard.
*/
#if OS2
/* The __open() system call translates "/dev/tty" to "con". */
tty = __open("/dev/tty", OPEN_READ);
#else
tty = open("/dev/tty", OPEN_READ);
#endif
if (tty < 0)
tty = 2;
Isn't file descriptor 2 stderr? If so, WTH?! I thought keyboard input was sent through stdin.
Interestingly, even if you do ls -l * | less
, after the file finishes loading, you can still use the keyboard to scroll up and down, but if you do ls -l * | vi
, then vi will yell at you because it doesn't read from stdin. What's the big idea? How did I end up in this strange new land where stderr is both a way to report errors to the screen and read from the keyboard? I don't think I'm in Kansas anymore...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
当在交互式终端上登录时,所有三个标准文件描述符都指向同一件事:您的 TTY(或伪 TTY)。
按照惯例,我们从
0
读取并写入1
和2
。然而,没有什么可以阻止我们采取其他行动。当您的 shell 运行 ls -l * | 时less,它创建一个从
ls
的文件描述符1
到less
的文件描述符0
的管道代码>.显然,less
无法再从文件描述符0
读取用户的键盘输入 - 它会尽其所能尝试恢复 TTY。如果
less
尚未与终端分离,open("/dev/tty")
将为其提供 TTY。但是,万一失败了……你能做什么?
less
最后一次尝试获取 TTY,假设文件描述符2
附加到与文件描述符0
附加的同一事物上,如果没有重定向。这不是防故障:
这里,
less
被赋予了自己的会话(因此它不再是终端活动进程组的一部分,导致open("/ dev/tty")
失败),并且其文件描述符2
已更改 - 现在less
立即退出,因为它正在输出到 TTY 但它无法获取任何用户输入。When logged in at an interative terminal, all three standard file descriptors point to the same thing: your TTY (or pseudo-TTY).
By convention, we read from
0
and write to1
and2
. However, nothing prevents us from doing otherwise.When your shell runs
ls -l * | less
, it creates a pipe fromls
's file descriptor1
toless
's file descriptor0
. Obviously,less
can no longer read the user's keyboard input from file descriptor0
– it tries to get the TTY back however it can.If
less
has not been detached from the terminal,open("/dev/tty")
will give it the TTY.However, in case that fails... what can you do?
less
makes one last attempt at getting the TTY, assuming that file descriptor2
is attached to the same thing that file descriptor0
would be attached to, if it weren't redirected.This is not failproof:
Here,
less
is given its own session (so it is no longer a part of the terminal's active process group, causingopen("/dev/tty")
to fail), and its file descriptor2
has been changed – nowless
exits immediately, because it is outputting to a TTY yet it fails to get any user input.嗯...首先,您似乎错过了打开“/dev/tty”的
open()
调用。如果调用 open() 失败,它仅使用文件描述符 2。在标准 Linux 系统(可能还有许多 Unices)上,“/dev/tty”存在并且不太可能导致失败。其次,顶部的注释对为什么它们回退到文件描述符 2 提供了有限的解释。我的猜测是
stdin
、stdout
和无论如何,stderr 几乎都连接到“/dev/tty/”,除非重定向。并且由于最常见的是 stdin 和/或 stdout 重定向(通过管道或
<
/>
),但较少用于stderr
,很有可能使用stderr
最有可能仍然连接到“键盘”。Well... first off, you seem to missing the
open()
call which opens '/dev/tty'. It only uses file descriptor 2 if the call to open() fails. On a standard Linux system, and probably many Unices, '/dev/tty' exists and is unlikely to cause a fail.Secondly, the comment at the top provides a limited amount of explanation as to why they fall back to file descriptor 2. My guess is that
stdin
,stdout
, andstderr
are pretty much connected to '/dev/tty/' anyway, unless redirected. And since the most common redirections for for stdin and/ or stdout (via piping or<
/>
), but less often forstderr
, odds on are that usingstderr
would be most likely to still be connect to the "keyboard".同样的问题最终来自提问者的答案,位于 linuxquestions 尽管它们引用的来源与
less
略有不同。不,我不明白其中的大部分内容,所以我无能为力:)The same question with an answer ultimately from the person who asked it is on linuxquestions although they quote slightly different source from
less
. And no, I don't understand most of it so I can't help beyond that :)这似乎是 Linux 特定功能,可将键盘输入发送到 FD 2。
It appears to be Linux specific functionality that sends keyboard input to FD 2.