我正在研究“ 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吗?如果是这样,是什么?我以为键盘输入是通过stdin发送的。
有趣的是,即使这样做ls -l * | less,在文件加载完成后,您仍然可以使用键盘上下滚动,但是如果这样做ls -l * | vi,则vi会大吼大叫,因为它不会从stdin中读取。有什么大主意?我如何最终进入这个陌生的新大陆,在那里stderr既是向屏幕报告错误又是从键盘读取信息的一种方式?我不认为我已经在堪萨斯州了…
ls -l * | less
ls -l * | vi
$ 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根根4 2009-09-13 01:57 / dev / stdin-> fd / 0 lrwxrwxrwx 1根根4 2009-09-13 01:57 / dev / stdout-> fd / 1 lrwxrwxrwx 1根根4 2009-09-13 01:57 / dev / stderr-> fd / 2
按照惯例,我们读出0和写入1和2。但是,没有什么可以阻止我们采取其他行动。
0
1
2
当你的shell运行时ls -l * | less,它创建了一个从管道ls的文件描述符1到less的文件描述符0。显然,less它不再能够从文件描述符中读取用户的键盘输入0-它会设法将TTY重新找回。
ls
less
如果less尚未从终端上拆下,open("/dev/tty")将给它TTY。
open("/dev/tty")
但是,如果失败了,该怎么办? less尝试最后一次获取TTY,假设文件描述符2附加到了文件描述符附加的同一对象0上(如果未重定向的话)。
这 不是 故障预防:
$ ls -l * | 少setsid 2> / dev / null
在这里,less为其分配了自己的会话(因此它不再是终端活动进程组的一部分,从而导致open("/dev/tty")失败),并且其文件描述符2已更改- 现在less立即退出,因为它正在输出到TTY,但无法获取任何用户输入。