2009-09-17 90 views
12

我正在看看'less'工具的代码,特别是它如何获得键盘输入。有趣的是,ttyin.c的80线,它设置文件描述符阅读:获取stderr的键盘输入较少?

 /* 
     * 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标准错误?如果是这样,WTH ?!我认为键盘输入是通过stdin发送的。

有趣的是,即使你ls -l * | less,文件加载完毕后,你仍然可以使用键盘上下滚动,但如果这样做ls -l * | vi,然后六将在骂你,因为它不会从标准输入读取。什么是大想法?我怎么最终在这个陌生的新土地上出现了stderr既是向屏幕报告错误又从键盘读取数据的方式?我不认为我在堪萨斯州...

+0

顺便说一句,如果你写'ls -l * | vim -',vim会执行类似的魔法。 – ephemient 2011-02-07 14:31:59

回答

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 

当登录Linux的特定功能在一个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的文件描述符1less的文件描述符0管道。显然,less不能再从文件描述符0 –读取用户的键盘输入,但它尝试获取TTY,但它可以。

如果less尚未从终端分离,open("/dev/tty")将给它TTY。

但是,如果失败...你能做什么? less最后一次尝试获取TTY,假设文件描述符2附加到文件描述符0将被附加到的相同的东西,如果它没有重定向。

不是 failproof:

 
$ ls -l * | setsid less 2>/dev/null 

这里,less给出了自己的会话(所以它不再是终端的活动进程组的一部分,造成open("/dev/tty")失败),并且其文件描述符2已被更改– now less立即退出,因为它正在输出到TTY,但它无法获得任何用户输入。

+3

+1,非常完整。 – 2009-09-17 21:21:40

+0

哦,我现在看到它。由于stderr不过是一个实际连接到终端的文件描述符,它可以根据需要读取或写入它。这很酷!谢谢你,ephemient。 – Michael 2009-09-18 13:51:24

+0

虽然文件描述符'2'只能写入,但是? – 2014-02-11 16:40:22

2

那么......首先,你似乎错过了打开'/ dev/tty'的open()调用。如果open()调用失败,它只使用文件描述符2。在一个标准的Linux系统上,可能还有很多Unices,'/ dev/tty'存在并且不太可能导致失败。

其次,在顶部的评论提供的解释数量有限,为什么他们回落到文件描述符2。我的猜测是,stdinstdout,并stderr都非常连接到“的/ dev/tty的/”无论如何,除非重定向。由于stdin和/或标准输出(通过管道或</>)最常见的重定向,但是对于stderr不太常见,使用stderr最有可能仍然连接到“键盘”的几率较低。

+0

使用stderr的原因是stdin/stdout更可能是由产卵shell创建的管道。进入或退出管道是一个noop,但确实有效。但重定向一个较少的命令stderr具有很小的价值,不可能完成。所以赌博stderr是“真的”终端设备是一个合理的猜测。 – 2009-09-17 21:55:45

1

同样的问题最终来自提问者的回答是linuxquestions,尽管他们引用与less略有不同的来源。不,我不明白大多数,所以我不能帮助超出了:)

-2

这似乎是把键盘输入到FD 2.

+1

公然错误。在任何其他UNIX上试试这个。 – ephemient 2009-09-17 21:09:14