less从stderr获取键盘input?

我正在看看“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读取并写入12 。 然而,没有什么阻止我们做其他事情。

当你的shell运行ls -l * | less ls -l * | less ,它创建一个从ls的文件描述符1less的文件描述符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.我的猜测是stdinstdoutstderr几乎连接到'/ dev / tty /',无论如何,除非重定向。 由于stdin和/或stdout(通过管道或< / > )最常见的重定向,但stderr不太常见,使用stderr最有可能仍然是连接到“键盘”。

同样的问题最终来自问这个问题的人的答案是在linuxquestions上,尽管他们引用的是稍微不同的来源。 不,我不明白其中的大部分,所以我无法超越那:)

它似乎是Linux特定的功能,将键盘输入发送到FD 2。