用抽象层控制交互式终端程序

Posted

技术标签:

【中文标题】用抽象层控制交互式终端程序【英文标题】:control an interactive terminal program with a layer of abstraction 【发布时间】:2018-10-22 09:02:01 【问题描述】:

我希望在终端中运行分页命令(通常是 git diff,但可能只是通过管道传输到 less 的我的其他程序),它是完全交互式的,但它是外部可控的。最初只是能够终止并重新启动内部进程就可以了,但是能够以交互方式注入输入会很好。

我认为一个简单的方法可能是使用一个简单地运行内部命令的 bash 脚本,我们假设它是 git diff

我将编写我的文本编辑器 vim 脚本,这样当我保存文件时,它会“发送一个信号”,上述 bash 脚本已以某种方式注册。在这种情况下,它将中断交互式子 less 进程(例如,给它一个 SIGTERM 似乎有点工作,尽管它无法重新绘制)并再次运行它。这样我就可以通过保存文件来实时更新我的​​ git diff。

我的其他用例可以使用相同的框架:我希望我的光标在我的编辑器中悬停的标记用于搜索项目,以查找它的所有其他实例。例如,这里的触发器将不同于保存缓冲区,并且比保存缓冲区更频繁。

应该保持交互性的原因(例如,终端连接到 STDIN)是为了让我可以使用鼠标/键在寻呼机内以交互方式上下滚动。

实现此目的的一种简单且看似脆弱的方法是将 vim 配置为直接给 less 一个 SIGTERM 或给父 git diff 一个 SIGKILL (仅从经验测试来看,这似乎在我的 Mac 上工作)。

但我希望如何杀死内部交互进程的逻辑和实现存在于 shell 脚本中。

我在想我可以使用 fifo 并发送一些由 shell 脚本解释的协议消息。但似乎发生的情况是终端交互式标准输入是通过 shell 脚本传递的……我可能还需要某种守护进程或由它管理的东西。需要有另一个组件监听该事件。

这让我想知道:也许这意味着一种更实用、更简单的实现方式是使用运行时(例如 node.js),它可以为我提供异步控制或其他 i/o 多路复用或异步 i/o 方法.它保持空闲状态,并通过管道/转发标准输入(交互)到子进程。它还异步侦听 fifo 或其他 IPC 方法,并将根据从它接收到的命令进行操作,例如注入进一步的交互式输入或杀死/重新启动孩子......

似乎应该有规范的 bashisms 来实现这一点,尽管我觉得我可能记得如何使用较低级别的 OS API 来做到这一点,例如 select(我在研究中通常记得是 i/o 多路复用) , 像这样的多路复用可能超出了 shell 的范围,shell 在 i/o redirection 周围有很多糖和能力。

【问题讨论】:

好吧,你有足够的声望知道你的问题看起来不像 MCVE。 你完全正确 这听起来像是你想创建一个 emacs 低级 shell,你可以控制、发送命令、搜索、保存等。如果你熟悉 emacs,这应该是直截了当的,如果不是,你可以忽略我的评论。 是的,但我是 Vim 人,另外,这里的主要目标是拥有一个 Vim(或任何其他程序)可以控制的单独终端。 【参考方案1】:

跟进我漫无边际的问题。

我继续沿着这条路走下去,并探索了一些选择。我或多或少正在构建一个 node.js 应用程序,该应用程序使用明确定义的(和非 terminfo 检查的)终端转义码来实现我自己的寻呼机工具,它可以完全按照我的意愿去做,不多也不少。

我也一直在围绕通过 tmux 实现的此功能构建自动化测试基础架构(例如,使用其 capture-pane 命令)。例如,为了测试分页是否正常工作,我可以在打开缓冲区后检查,在向下滚动 3 页并备份 2 页后,输出是否与在 1 页后显示的内容相同。

尽管可以很好地认为它可能应该只是一个简单的 ncurses 应用程序,但我发现它是一种有益的体验,可以深入了解这些东西并继续使用 typescript,我已经为其他任务写了很多,它有助于继续积累使用该语言的经验。对于这种专门构建的工具来说,当然不是理想的语言或运行时,但没关系。

【讨论】:

以上是关于用抽象层控制交互式终端程序的主要内容,如果未能解决你的问题,请参考以下文章

第九章硬件抽象层:HAL

expect自动化交互式操作

10.21 作业控制信号

teminal / console / shell

系统思维--系统的思维分层抽象

Spring数据访问和数据访问层与业务或服务层之间的交互