我怎样才能让“clear”保留整个回滚缓冲区?

我怎样才能让“clear”保留整个回滚缓冲区?

每当我clear在终端中运行时,它都会从屏幕可见部分的顶部到当前行删除回滚缓冲区。我在多个终端仿真器中尝试过,但问题仍然存在。有什么方法可以改变的行为,使其clear不触及回滚缓冲区?

我的终端之前的clear命令:

“清除”命令前的终端

clear命令执行后回滚缓冲区

“清除”命令后回滚缓冲区

答案1

分析

您称这种行为“奇怪”,但这是设计使然。clear它不会将文本移出屏幕,而是清除屏幕上显示的内容。严格来说,它只是告诉终端(终端仿真器)执行此操作。

在某些终端中,clear可以有效地清除整个回滚缓冲区。至少clear在我的 Kubuntu 中可以这样做;-x我可以要求它不要这样做。请参阅man 1 clear

我的$TERMxterm-256color,这clear对我来说是有效的:

$ clear | od -c
0000000 033   [   H 033   [   2   J 033   [   3   J
0000013
$ clear -x | od -c
0000000 033   [   H 033   [   2   J
0000007

clear -x相当于printf '\033[H\033[2J'
soleclear相当于printf '\033[H\033[2J\033[3J'

这些序列ANSI 转义代码.终端应该解释它们。

缩写 姓名 影响
CSI n ; m H 杯子 光标位置 将光标移动到行n、列m。[…]
CSI n J ED 显示中擦除 清除部分屏幕。[…]

注意clear打印的内容很大程度上取决于$TERM。例如,如果我选择一个“随机”终端:

$ TERM=ztx clear | od -c
0000000 033   E
0000002

上面clear没有使用 ED;而是使用了 CNL:

缩写 姓名 影响
CSI n E 中央核能实验室 光标下一行 将光标向下移动到行首n(默认1)。[…]

这并没有清除我的终端的屏幕。或许在实际中确实如此ztx;或者不,我不知道。无论如何clear“认为”终端是ztx,并且对于ztxCNL 来说是最好的选择。

无论如何,我们都可以构建并使用等效printf命令。 的重点clear是它会检查$TERM环境,然后查看 terminfo 数据库(请参阅man 5 terminfo)以确定如何清除屏幕。 而printf我们需要手动执行此操作。

clear在某些情况下(即对于某些值$TERM),的某些实现打印出您想要的序列并非不可能。

然后是终端(终端模拟器)。即使clear打印\033[2J,终端也可能反应做你想做的事。也许有一个选项让你选择。你可以编写一个以这种方式做出反应的终端仿真器。

我经常使用 tmux,它实现了自己的回滚缓冲区。在内部它$TERM扩展为screenclear并且clear -x都等同于printf '\033[H\033[J'。当由 tmux 解释时,此序列会执行您想要的操作。但在 tmux 之外(在我的情况下,使用 Konsole 提供的回滚缓冲区),相同的序列会重现您的问题。我推断 tmux 是一个按您想要的方式做出反应的终端仿真器。

我的观点是:clear根据终端“认为”的是什么,打印不同的东西;然后终端解释这些东西,并可能以任何方式做出反应。例如,你的clear似乎做了我clear -x所做的:它没有清除整个回滚缓冲区,只清除可见部分。所以也许你的clear没有打印\033[3J;或者也许它确实打印了,但你的终端无论如何都没有完全清除缓冲区。

或许$TERM你可以找到不同的值你的 clear咨询你的terminfo 数据库将能够你的终端仿真器可以做你想做的事。即使你能做到这一点,我也不认为这是正确的事情。改变$TERM可能会破坏其他事情。


解决方案 1:tmux

使用 tmux 及其回滚缓冲区。我的测试表明它的行为符合您的要求(至少在clear显示$TERM为 时screen)。该工具是一个终端多路复用器,我经常使用它,因为它其他 特征我必须明确地跳出这个思路来写这个答案的某些部分。

这可能是您在终端中工作方式的重大变化。在我看来观点这是值得的。请注意,使用 tmux 的回滚缓冲区与使用终端仿真器的回滚缓冲区在许多方面都不同。

至少考虑尝试一下 tmux。


解决方案 2:自定义clear为 shell 函数

看起来您不想清除任何东西;您想将文本移出屏幕并将提示放在顶部。因此,让我们这样做:

clear() (
   if [ "$#" -ne 0 ]; then
      command clear "$@"
      exit
   fi
   h="$(tput lines 2>/dev/null)"
   if [ "$?" -eq 0 ]; then
      until [ "$h" -le 1 ]; do
         printf '\n'
         h=$((h-1))
      done
   fi
   command clear -x
)

函数clear在不带参数调用时会覆盖命令;否则,它会返回命令。当它覆盖时,函数会打印正确数量的换行符,以将先前的内容移出屏幕;然后clear -x调用常规来清除换行符并将提示符放在顶部。

笔记:

  • tput lines不可移植。如果此命令存在任何问题,则该函数将仅调用command clear -x
  • command clear -x假设您的clear可执行文件支持-x与我的一样。从您不需要的问题来看-x,您的唯一方法clear不会清除整个缓冲区(可能是因为您的clear不同;可能是因为您的终端不同)。printf '\033[H\033[2J'改为调用可能就足够了。另一方面,command clear …查阅 terminfo 数据库,这也是您可能希望从该函数中获得的功能。根据您的需要调整该函数。
  • 如果在函数运行时调整终端仿真器的大小,则函数可能会出现错误。如果需要调整大小,请在调用之前或之后进行clear,而不是在调用期间。
  • 该函数可以在 tmux 内部使用。它在那里绝对不需要(因为 tmux 本身就是一个解决方案),但据我所知,它不会破坏任何东西。因此,例如,~/.bashrc如果您在 tmux 之外使用 Bash,则可以将该函数放在您的程序中,当您在 tmux 内部使用 Bash 时,一切仍然应该正常工作。
  • 任何 shell 函数都是在 shell 中定义的。我们的代码可以转换为脚本(包装器),clear无论使用哪种 shell,都可以覆盖该脚本。

答案2

从手册页来看,clear -x不会清除回滚缓冲区。

答案3

简短、便携的答案:

tput indn $LINES
... 将使当前终端“向上”滚动其所含的行数。
效果是“清除”屏幕,而不会丢失任何滚动缓冲区内容。

如其他地方所示:
tput indn $LINES | od -t x1z
...将显示正在发生的事情。(十六进制,此处附有字符解释)

man terminfo获得更多选项。

完全可以放入别名甚至是 bash 函数。

函数 scroll_up {
  输入 indn $LINES
}

注意:(shopt -s checkwinsize更多信息;man bash)应该在您的$HOME/.bashrc$HOME/.bash_aliases- 就像scroll_up上面的功能一样。

还有一个注意事项:为了扩展可移植性,请确保shopt ...使用
LINES=$(tput lines)

相关内容