退出后,某些工具(例如 nano ,less)如何设法在终端中不留下任何内容?

hum*_*ace 41 pager terminal escape-characters

每当我在 shell 中使用类似寻呼机less或编辑器nano(我的 shell 是 GNU bash)时,我都会看到一种我无法完全解释的行为,这与我可以使用其他工具(如catls. 我想问一下这种行为是怎么产生的。

不容易解释的行为是,通常所有输出到 stdout/stderr 最终都被记录在终端模拟器后台缓冲区中,所以我可以向后滚动,而在使用lessor的情况下(对我来说不太正常)nano,输出由终端模拟器显示,但在退出程序时,内容“神奇地消失”。

我想举两个例子:

  • seq 1 200 (在后台缓冲区中生成 200 行)
  • seq 1 200 | less (让我翻页 200 行,但最终“清理”并在后台缓冲区中没有记录任何内容)

我的怀疑是某种转义代码在起作用,我很感激有人指出我对这种观察到的行为差异的解释。

由于一些评论和答案是措辞的,就好像我希望改变行为一样,这“很高兴知道”,但实际上所需的答案应该是对机制的描述,而不是改变它的方法。

Jde*_*eBP 44

这里有两种世界观:

  • 就使用 termcap/terminfo 的程序而言,您的终端可能有两种模式:光标寻址模式滚动模式。后者是普通模式,当程序需要按行和列地址在屏幕上移动光标时,程序切换到光标寻址模式,将屏幕视为一个二维实体。

    termcap 和 terminfo 处理将这个世界观(程序所看到的)转换为终端所看到的世界观。

  • 就终端(仿真或真实)而言,有两个屏幕缓冲区,任何时候都只显示其中一个。有一个主屏幕缓冲区和一个备用屏幕缓冲区。程序发出的控制序列在两者之间切换终端。
    • 对于某些终端,通常是模拟终端,备用屏幕缓冲区是根据 termcap/terminfo 的使用量身定制的。它们的设计知道切换到光标寻址模式的一部分是切换到备用屏幕缓冲区,而切换到滚动模式的一部分是切换到主屏幕缓冲区。这就是 termcap/terminfo 的翻译方式。因此,当显示备用屏幕缓冲区时,这些终端不会显示滚动用户界面小部件,并且根本没有该屏幕缓冲区的回滚机制。
    • 对于其他终端,通常是真实终端,备用屏幕缓冲区与主屏幕缓冲区非常相似。两者在支持的内容方面基本相同。请注意,一些仿真终端属于此类。例如,Unicode rxvt 具有主屏幕缓冲区和备用屏幕缓冲区的回滚功能。

呈现全屏文本用户界面的程序(如vimnanolessmc等)使用 termcap/terminfo 在启动时切换到光标寻址模式,并在挂起、退出或退出时返回滚动模式. ncurses 库可以这样做,但不使用 ncurses 的程序也可以这样做,这些程序更直接地构建在 termcap/terminfo 之上。

less或呈现的 TUI 中的滚动vim与回滚无关。这是在这些程序中实现的,这些程序只是在滚动时适当地重新绘制其全屏文本用户界面。

请注意,这些程序不会在备用屏幕缓冲区中“留任何内容”。终端不再显示他们留下的东西。

  • 这对于某些平台上的 Unicode rxvt 尤其明显,其中用于切换到光标寻址模式的 termcap/terminfo 序列不会隐式清除备用屏幕缓冲区。因此,连续使用多个这样的全屏 TUI 程序最终可能会显示上一个程序留下的备用屏幕缓冲区的旧内容,至少在新程序写入其输出之前的一段时间内(最明显的less是在管道的末端)。
  • 使用 xterm,您可以从终端仿真器的 GUI 菜单切换到显示备用屏幕缓冲区,并在那里看到内容。

实际控制序列是相关标准所称的设置私有模式控制序列。相关的私有模式编号是 47、1047、1048 和 1049。注意除了切换到/从备用屏幕缓冲区之外,每个模式隐含的额外操作的差异。

进一步阅读


ctr*_*lor 5

一个名为 curses 的库,它知道您使用的是哪种终端类型,并发送正确的转义序列。有终端被要求切换到不同的垂直缓冲区,以及允许更多控制的模式。


L. *_*mes 5

您可以通过几种方式添加 no-clear 。您可以less通过使用参数调用它来解决清除屏幕的问题-X

请注意$下面命令行中的符号。这是指定普通用户的终端提示符。

$ seq 1 200 | less -X
Run Code Online (Sandbox Code Playgroud)

如果这是您想要的行为,您可以less将此默认值别名为:

$ alias less='less -X'
Run Code Online (Sandbox Code Playgroud)

其他程序也有类似的解决方法。

或者,您可以添加自己的终端定义,而不是尝试单独配置每个应用程序。在本例中,我将其称为xterm-noclear

运行以下步骤来创建新的 xterm 定义:

$ infocmp -I xterm > xterm-noclear.src
$ gedit xterm-noclear.src
Run Code Online (Sandbox Code Playgroud)

现在将编辑器中的第二行从 更改xtermxterm-noclear

通过搜索rmcupsmcup删除清除屏幕的指令,并删除这两个指令:

smcup=\E[?1049h,
Run Code Online (Sandbox Code Playgroud)

rmcup=\E[?1049l, 
Run Code Online (Sandbox Code Playgroud)

保存文件,然后添加终端定义:

$ tic ~/xterm-noclear.src
Run Code Online (Sandbox Code Playgroud)

您可以使用以下命令将其设为系统范围内可用的终端定义:

$ sudo tic ~/xterm-noclear.src
Run Code Online (Sandbox Code Playgroud)

现在您可以将其用于TERM

$ export TERM=xterm-noclear
Run Code Online (Sandbox Code Playgroud)