我正在查看'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?如果是这样,WTH?!我以为键盘输入是通过stdin发送的。
有趣的是,即使您执行ls -l * | less
,文件加载完毕后,仍然可以使用键盘上下滚动,但如果执行ls -l * | vi
,那么vi会对你大喊大叫,因为它不会从标准输入读取。什么是重要的想法?我怎么会在这个奇怪的新土地上结束,stderr既可以向屏幕报告错误并从键盘读取?我不认为我在堪萨斯州了......
答案 0 :(得分:19)
$ ls -l /dev/fd/ lrwx------ 1 me me 64 2009-09-17 16:52 0 -> /dev/pts/4 lrwx------ 1 me me 64 2009-09-17 16:52 1 -> /dev/pts/4 lrwx------ 1 me me 64 2009-09-17 16:52 2 -> /dev/pts/4
在交互式终端登录时,所有三个标准文件描述符都指向同一个东西:您的TTY(或伪TTY)。
$ ls -fl /dev/std{in,out,err} lrwxrwxrwx 1 root root 4 2009-09-13 01:57 /dev/stdin -> fd/0 lrwxrwxrwx 1 root root 4 2009-09-13 01:57 /dev/stdout -> fd/1 lrwxrwxrwx 1 root root 4 2009-09-13 01:57 /dev/stderr -> fd/2
按照惯例,我们从0
开始阅读并写信给1
和2
。但是,没有什么能阻止我们这样做。
当shell运行ls -l * | less
时,它会创建一个从ls
的文件描述符1
到less
的文件描述符0
的管道。显然,less
无法再从文件描述符0
读取用户的键盘输入 - 它会尝试尽快恢复TTY。
如果less
未与终端分离,open("/dev/tty")
会将其提供给TTY。
但是,如果失败了......你能做什么? less
最后一次尝试获取TTY,假设文件描述符2
附加到文件描述符0
将被附加到的同一事物上,如果它没有被重定向。< / p>
不防止失败:
$ ls -l * | setsid less 2>/dev/null
这里,less
被赋予了自己的会话(因此它不再是终端的活动进程组的一部分,导致open("/dev/tty")
失败),其文件描述符2
具有已更改 - 现在less
立即退出,因为它输出到TTY但它无法获得任何用户输入。
答案 1 :(得分:2)
嗯......首先,您似乎错过了打开'/ dev / tty'的open()
调用。如果对open()的调用失败,它只使用文件描述符2。在标准的Linux系统上,可能还有很多Unices,'/ dev / tty'存在并且不太可能导致失败。
其次,顶部的评论提供了有限的解释,说明为什么它们会回退到文件描述符2.我的猜测是stdin
,stdout
和stderr
是几乎连接到'/ dev / tty /',除非重定向。并且由于stdin和/或stdout的最常见重定向(通过管道或<
/ >
),但stderr
的频率较低,因此使用stderr
的可能性很小最有可能仍然连接到“键盘”。
答案 2 :(得分:1)
同样的问题及答案最终来自提出问题的人linuxquestions,尽管他们引用了与less
略有不同的来源。不,我不理解其中的大部分因此我无法超越那个:)
答案 3 :(得分:-2)
它似乎是特定于Linux的功能,它将键盘输入发送到FD 2。