我正在看一下“更少”实用程序的代码,特别是如何获取键盘输入.有趣的是,在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 * |较少,在文件完成加载后,您仍然可以使用键盘上下滚动,但如果您执行ls -l * | vi,那么vi会对你大喊大叫,因为它没有从stdin读取.有什么大的想法?在这个陌生的新土地上,我最终是如何把sterrr都报告给屏幕并从键盘读取的?我不认为我在堪萨斯了…
解决方法
$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 * |较少,它创建一个从ls的文件描述符1到较少的文件描述符0的管道.显然,较少的不能再从文件描述符0读取用户的键盘输入 – 它试图获得TTY返回,但它可以.
如果没有离开终端,打开(“/ dev / tty”)会给它TTY.
但是,如果失败了…你能做什么?最后一次尝试获取TTY,假设文件描述符2附加到文件描述符0将被附加到相同的东西,如果它没有被重定向.
这不是防故障的:
$ls -l * | setsid less 2>/dev/null
在这里,给定自己的会话较少(因此它不再是终端活动进程组的一部分,导致open(“/ dev / tty”)失败),并且其文件描述符2已更改 – 现在较少立即退出,因为它输出到TTY,但它无法获得任何用户输入.