【问题标题】:Writing my own shell: How implement command history? [closed]编写我自己的 shell:如何实现命令历史记录? [关闭]
【发布时间】:2016-05-11 05:32:46
【问题描述】:

作为一个更好地理解我的计算机的练习,作为一个工具,我正在用 C++ 编写my own shellStephen Brennan's article on writing a simple shell 很有帮助。

然而,让我困惑的是如何处理按向上箭头和向下箭头滚动浏览我的命令历史记录。

  • 我尝试了ncurses,但这会替换整个屏幕,而系统提供的 shell 似乎只是继续写入终端。

  • 我尝试使用 tcgetattr 关闭规范模式,但是虽然这让我可以在键入时按下箭头键,但它也会关闭对文本导航的左/右箭头键的所有处理,并且退格键和 Ctrl-C ...虽然我自己可能会发送一个信号来响应 Ctr-C,但我不知道如何让终端将光标移回(除了输出“返回”并重新写行的开头)。它似乎也给了我不同的转义序列,这取决于我是在 Xcode 的“哑”终端还是在我的 Mac 的 Terminal.app 中运行。

  • 我查看了 fish Shell 和 bash 的来源,但似乎太多内容无法找到相关部分。 p>

标准外壳如何处理接收按键?他们如何处理移动光标和退格?他们如何在不占用屏幕的情况下重写一行的部分内容?是否有一个标准来定义外壳需要做什么?

PS - 我知道如何记录以前的命令。实际上是在键入时得到按键,而不是在有人按下返回之后,我无法开始工作。

【问题讨论】:

  • 使用GNU readline 或等效的BSD editline
  • Close-voters:我希望你已经阅读了更新后的问题,现在看起来很好:)
  • 我根本不知道它实际上是如何实现的,但我怀疑 shell 正在重写整个屏幕(à la ncurses)。例如,如果我在bash 中按 C-l,它将清除整个屏幕。这表明 shell 不仅仅是一次管理一行。我认为像 readline 这样的库同样会接管整个终端。
  • @WaleedKhan 他们不会接管屏幕。 Terminal.app 默认为 bash。如果我现在输入ksh 并按回车键,我会得到一个 Korn Shell,它会愉快地继续在前面的 bash 命令下面编写。因此,必须有一种方法可以让完全不同的可执行文件取代前一个可执行文件中断的地方。
  • @uliwitness 我认为您可以只查询当前光标位置的位置,然后从那里继续写入。我不使用ncurses 或类似的,所以我不能肯定地说。

标签: c++ unix


【解决方案1】:

您必须关闭 ICANONECHO 并自己解释箭头键的转义序列。

您必须为屏幕上的内容和光标所在位置保留自己的“实际”缓冲区。您还需要一个“想要的”缓冲区,其中包含您想要在屏幕上显示的内容以及您想要光标的位置。这些缓冲区不会覆盖整个屏幕,只是包含提示和用户输入的行(您手动回显,因为您关闭了ECHO)。由于您在这些行上打印了所有内容,因此您知道它们的内容。

就在您等待下一个输入字节之前,您更新屏幕以匹配所需的缓冲区。当您使用 300(甚至 9600)波特率连接时,您非常关心通过寻找可打印字节和终端控制序列的最佳序列来将实际缓冲区转换为所需缓冲区,从而尽可能高效地进行更新。如今,优化已变得不那么重要了。

如果输入换行,这些缓冲区将跨行,因此您需要知道并跟踪终端宽度(使用TIOCGWINSZSIGWINCH)。您可以坚持使用水平滚动而不是换行的单行,但您仍然需要知道终端宽度。

理论上,您可以在 termcap 或 terminfo 数据库中查找您的终端类型(来自 $TERM)。这会告诉您当用户按下特殊键(箭头、home、end 等)时期望什么转义序列,以及发送哪些转义序列来移动光标、清除屏幕部分、插入或删除字符或行等.

如今,假设一切都与 xterm 相当兼容是相当安全的,尤其是对于爱好项目。

对于 bash,这一切都在 GNU readline 库中完成。更新屏幕(称为“重新显示”)在display.c 中完成。输入转义解码在input.c完成。

但是,如果您想要示例代码,您可能应该查看linenoise,它不到 2000 行。它假定终端兼容 VT100(因此 xterm)。

另见“Is there a simple alternative to Readline?”

【讨论】:

    猜你喜欢
    • 2015-12-18
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 2018-01-30
    • 2011-06-16
    • 1970-01-01
    • 2021-06-24
    • 2013-05-12
    相关资源
    最近更新 更多