交互式命令行实用程序实际上是如何工作的?
我掌握了标准输入、标准输出、标准错误的基本概念以及程序如何与命令行/终端一起工作。
然而,我一直想知道 Linux 中的 less
和 git log
等实用程序是如何工作的,因为它们是交互式的。
我当前的想法是,程序不会退出,而是写入标准输出,侦听关键事件并向标准输出写入更多内容,直到用户退出按 q
或发送关闭信号。
我的直觉是正确的还是还有更多的内容?他们是否检测行数和每行字符数来确定输出多少?他们在输出之前总是清除屏幕吗?
I grasp the basic concept of stdin, stdout, stderr and how programs work with a command line/terminal.
However, I've always wondered how utilities like less
in Linux and git log
work because they are interactive.
My current thought is that the program does not quit, writes to stdout, listens to key events and writes more to stdout until the user quits pressing q
or sends the close signal.
Is my intuition right or is there more to it? Do they detect the amount of lines and characters per line to determine how much to output? And do they clear the screen always before output?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
非常有趣的问题,即使它有点开放式。
正如 @tripleee 所提到的,ncurses 是交互式 CLI 应用程序的基础库。
一点历史...
终端==“打印机”...
要理解 POSIX“终端”,您必须考虑它们的历史...更具体地说,您需要考虑一下“终端”在 70 年代的含义,当时您将键盘+打印机连接到串行电缆。当您键入时,字节流流向主机,主机将它们回显给打印机,从而使打印机在您键入命令时回显命令。然后,通常在按 ENTER 键后,主机将关闭并执行一些工作,然后将输出发送回进行打印。因为它基本上是一个美化的点阵打印机,所以我们在这里讨论的是仅附加。没有“绘制屏幕”或任何类似的花哨的东西。
试试这个:
你会看到它打印出“再见”。 “\r”是回车,不换行。 托架是在旧式点阵打印机中来回移动的打印机部件,实际上印刷。因此,如果您将笔架返回到页面左侧并且无法推进纸张(即“换行”),那么您将开始打印当前的文本行。 “终端”==“打印机”。
监视器和软件终端......仍然是面向线路的
所以快进一点,一种称为“监视器”的革命性技术出现了,您可以拥有一个虚拟化的终端显示重写。因此,像所有优秀的技术一样,我们通过添加越来越多的特殊转义码来逐步创新。例如,查看 ANSI 颜色代码。如果您使用的终端无法识别这些转义码,您将在这些未解释的代码的输出中看到一堆乱码:
当您的终端看到 '\033' (ESC)、'[', ... , 'm',它将其解释为更改颜色的命令。试试这个:
无论如何,这就是 Unix 终端系统的历史/遗产,然后被 Linux 和 BSD(例如 Macs)继承,并半标准化为 POSIX。查看termio.h,它定义了内核接口与终端交互。几乎可以肯定,Linux/BSD 有许多更高级的功能,但尚未完全标准化为 POSIX。在谈论“标准”时,还有一堆事实上的终端设备协议标准,例如古老的 VT100。 SSH 或 PuTTY 等软件“终端仿真器”知道如何使用 VT100,通常还知道如何使用一系列更高级的方言。
将“交互”硬塞到“面向线路”的界面上...
所以...交互...不太适合线路-打印机的世界观。它分层在上面。输入简单;而不是自动回显每次键入的按键并等待 ENTER (ala "readline"< /a>),我们让程序消耗来自 TTY 的击键。输出更复杂。尽管基本抽象是输出流,但有了足够的转义码,您可以通过定位 "caret" 并在旧文本之上写入新文本(就像我的“\r”示例一样)。自己实现这些都不是一件有趣的事情,特别是当您想要支持具有不同转义码的多个环境时。 .... 因此,ncurses 是其中最著名的库之一。要了解如何有效地将动态屏幕渲染为面向行的 TTY,请查看 输出和屏幕更新来自“NCURSES 黑客指南”。
Very interesting question, even if it's a bit open ended.
As mentioned by @tripleee, ncurses is a foundational library for interactive CLI apps.
A bit of history ...
Terminal == "printer" ...
To understand POSIX "terminals", you have to consider their history ... more specifically, you need to think about what a "terminal" meant in the 70's where you'd have a keyboard+printer attached to a serial cable. As you type, a stream of bytes flows to the mainframe which echos them back to the printer causing the printer to echo the command as you type it. Then, typically after pressing ENTER, the mainframe would go off and do some work and then send output back to be printed. Since it basically a glorified dot-matrix printer, we are talking append-only here. There was no "painting the screen" or anything fancy like that.
Try this:
and you'll see it print "Bye there". "\r" is a carriage return with no line feed. A carriage is that printer part that moves back and forth in an old dot-matrix printer and actually does the printing. So if you return the carriage back to the left side of the page and fail to advance the paper (ie, "line feed"), then you will start printing over the current line of text. "terminal" == "printer".
Monitors and software terminals ... still line-oriented
So flash forward a bit and a revolutionary tech called "monitors" comes about where you have a virtualized terminal display that can be rewritten. So like all good tech, we innovated incrementally by adding more and more special escape codes. For example, check out the ANSI color codes. If you are on a terminal that doesn't recognize those escape codes, you'll see a bunch of gibberish in the output from those uninterpreted codes:
When your terminal sees '\033' (ESC), '[', ..., 'm', it interprets it as a command to change the color. Try this:
So anyways, that's the history/legacy of the Unix terminal system which was then inherited by Linux and BSD (eg, macs), and semi-standardized as POSIX. Check out termio.h which defines the kernel interface for interacting with terminals. Almost certainly, Linux/BSD have a bunch of more advanced functions that aren't fully standardized into POSIX. While talking about "standards", there's also a bunch of de-facto terminal device protocol standards like the venerable VT100. Software "terminal emulators" like SSH or PuTTY know how to speak VT100 and usually a bunch of more advanced dialects as well.
Shoe-horning "interactive" onto a "line-oriented" interface ...
So ... interactive ... that doesn't really fit well with a line-printer view of the world. It's layered on top. Input is easy; instead of automatically echoing each keystroke typed and waiting for ENTER (ala "readline"), we have the program consume keystrokes as they come in from the TTY. Output is more complex. Even though the fundamental abstraction is a stream of output, with enough escape codes you can repaint the screen by positioning the "caret" and writing new text on top of old text (just like with my "\r" example). None of this is fun to implement yourself, especially when you want to support multiple environments with different escape codes. .... thus the libraries, of which ncurses is one of the most well known. To get an idea of the funky magic done to efficiently render a dynamic screen into a line-oriented TTY, check out Output and Screen Updating from "A Hacker's Guide to NCURSES".