我正在看看“less”工具的代码,特别是它如何得到键盘input。 有趣的是,在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? 我认为键盘input是通过stdin发送的。
有趣的是,即使你做了ls -l * | less
ls -l * | less
,在文件加载完成后,仍然可以用键盘上下滚动,但是如果你做了ls -l * | vi
ls -l * | vi
,那么vi会因为不从标准input读取而吼你。 什么是大想法? 我怎么最终在这个陌生的新地方,stderr既是向屏幕报告错误,又从键盘读取的方法? 我不认为我在堪萨斯州了…
$ 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
在interative终端上登录时,所有三个标准文件描述符指向相同的东西:您的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 -l * | less
,它创建一个从ls
的文件描述符1
到less
的文件描述符0
的管道。 显然, less
不能再从文件描述符0
读取用户的键盘输入 – 它试图得到TTY,但它可以。
如果还没有脱离终端, open("/dev/tty")
会给它TTY。
但是,如果失败…你能做什么? 如果没有重定向,那么假设文件描述符2
被附加到与文件描述符0
将被附加到的东西相同的东西上,则最后一次尝试获取TTY。
这不是失败的:
$ ls -l * | setsid less 2> / dev / null
在这里,给它自己的会话less
(所以它不再是终端活动进程组的一部分,导致open("/dev/tty")
失败),并且其文件描述符2
已经改变 – 现在立即退出,因为它正在输出到TTY,但它没有得到任何用户输入。
那么…首先,你似乎错过了打开“/ dev / tty”的open()
调用。 如果调用open()失败,它只使用文件描述符2。 在标准的Linux系统上,可能还有很多Unices,“/ dev / tty”存在,不太可能导致失败。
其次,上面的注释提供了有限的解释,为什么他们回落到文件描述符2.我的猜测是stdin
, stdout
和stderr
几乎连接到'/ dev / tty /',无论如何,除非重定向。 由于stdin和/或stdout(通过管道或<
/ >
)最常见的重定向,但stderr
不太常见,使用stderr
最有可能仍然是连接到“键盘”。
同样的问题最终来自问这个问题的人的答案是在linuxquestions上,尽管他们引用的是稍微不同的来源。 不,我不明白其中的大部分,所以我无法超越那:)
它似乎是Linux特定的功能,将键盘输入发送到FD 2。