`less` 如何从标准输入获取数据,同时仍然能够读取用户的命令?

iBu*_*Bug 48 less

正如大多数人已经做过很多次一样,使用less以下命令查看长文本很方便:

some_command | less
Run Code Online (Sandbox Code Playgroud)

现在它的标准输入连接到一个管道(FIFO)。它怎么还能读取像 up/down/quit 这样的命令?

Ste*_*itt 53

正如William Pursell所提到的,less从终端读取用户的击键。它明确地打开/dev/tty,控制终端;这给了它一个文件描述符,与标准输入分开,它可以从中读取用户的交互式输入。如有必要,它可以同时从其标准输入读取数据以显示。(如有必要,它也可以直接写入终端。)

您可以通过运行看到这种情况发生

some_command | strace -o less.trace -e open,read,write less
Run Code Online (Sandbox Code Playgroud)

移动 input, exitless并查看 : 的内容,less.trace您将看到它 open /dev/tty,并从文件描述符 0 和打开时返回的任何一个/dev/tty(可能是 3)中读取。

对于希望确保它们正在从终端读取和写入终端的程序来说,这是一种常见的做法。一个例子是 SSH,例如,当它要求输入密码或密码时。

正如schily解释的,如果无法打开,将从其标准错误(文件描述符 2)中读取。的使用是在 1991 年 4 月 2 日发布的版本 177 中引入的。/dev/ttylessless/dev/tty

如果您尝试运行cat /dev/tty | less,如Hagen von Eitzen建议的那样,将成功打开,但在关闭它之前不会从中获得任何输入。所以你会看到屏幕空白,直到你按下杀死(或以其他方式杀死它);then将显示您在运行时输入的任何内容,并允许您控制它。less/dev/ttycatCtrlCcatlesscat

  • @grawity 我认为 Andrew 的观点是 `cat blah |` 可以被替换为 `< blah`,在这种情况下甚至这也是不必要的,因为 `less blah` 也可以工作(好吧,`less -f /dev/tty`)。但是从 `/dev/tty` 读取是一个特殊情况,所有三个变体(`cat /dev/tty | less`、`less < /dev/tty` 和 `less -f /dev/tty` ) 产生不同的结果。 (8认同)
  • @HagenvonEitzen 哇。双重[无用使用 cat](http://porkmail.org/era/unix/award.html#cat)。我很感动。 (7认同)
  • @HagenvonEitzen 你的电脑会爆炸!就像柯克和史波克让穆德的机器人崩溃一样。 (4认同)
  • @StarWeaver 看到 [this question](https://unix.stackexchange.com/q/447197/86440) 关于 `/dev/tty` 和 `/dev/pts/...` 之间的区别。 (2认同)

sch*_*ily 28

UNIX 提供了两种方法来读取用户输入,而 stdin 已被重定向:

  • 原始方法是从stderr读取。标准错误是开放的写作阅读,这仍然是POSIX提及。

  • 后来的 UNIX 版本(大约 1979 年)添加了一个/dev/tty驱动程序接口,允许打开进程的控制 tty。由于存在没有控制 tty 的进程,因此打开尝试可能会/dev/tty失败。因此,友好的编写软件会退回到原始方法,然后尝试从 stderr 读取。

  • 从标准错误读取?学到了新东西。 (12认同)
  • 是的,这是因为这是最不可能被重定向的文件描述符。 (4认同)
  • 是不是stderr 用于读取的原因,是因为它被重定向的可能性最小?我没有看到它与标准输出(或重定向之前的标准输入)之间的任何其他区别。 (3认同)