我正在查看'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?如果是这样,WTH ?!我以为键盘输入是通过stdin发送的。

有趣的是,即使你做了ls -l * | less,在文件加载完成后,你仍然可以使用键盘上下滚动,但如果你做ls -l * | vi,那么vi会对你大喊大叫,因为它没有从stdin读取。什么是重要的想法?我怎么会在这个奇怪的新土地上结束,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

在交互式终端登录时,所有三个标准文件描述符都指向同一个东西:您的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的文件描述符lessopen("/dev/tty")的文件描述符<=>创建一个管道。显然,<=>无法再从文件描述符中读取用户的键盘输入<=> <!>#8211;它会尽力让TTY回来。

如果<=>尚未从终端分离,<=>将为其提供TTY。

但是,如果失败了......你能做什么? <=>最后一次尝试获取TTY,假设文件描述符<=>附加到文件描述符<=>将被附加到的同一事物上,如果它没有被重定向。

防止失败:

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

这里,<=>被赋予自己的会话(因此它不再是终端的活动进程组的一部分,导致<=>失败),并且其文件描述符<=>已被更改<!># 8211;现在<=>立即退出,因为它输出到TTY但它无法获得任何用户输入。

其他提示

嗯......首先,您似乎错过了打开'/ dev / tty'的open()电话。如果对open()的调用失败,它只使用文件描述符2。在标准的Linux系统上,可能还有许多Unices,'/ dev / tty'存在,不太可能导致失败。

其次,顶部的评论提供了有限的解释,说明为什么它们会回归到文件描述符2.我的猜测是stdinstdoutstderr几乎与'/ dev / tty /'无论如何,除非重定向。并且由于stdin和/或stdout最常见的重定向(通过管道或< / >),但<=>的次数较少,因此使用<=>的可能性最大的仍然是连接到<!>“键盘<!>”;。

同样的答案最终来自提出答案的人在 linuxquestions 尽管他们引用了与less略有不同的来源。不,我不理解其中的大部分因此我无法超越那个:)

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top