如何在Bash中将键盘和命名管道连接到STDIN?

时间:2010-11-25 05:21:42

标签: bash interprocess

我正在尝试找到一种方法来调用交互式命令行程序,以便它既可以直接从键盘输入,也可以从命名管道输入。我的目标是让这个与MATLAB一起工作,但我认为Bash和一个例子一样好用。因此,我们的想法是启动Bash,一旦它运行,我就可以输入命令,使用箭头表示历史记录等,并将命令发送到命名管道。我一直在四处寻找并摆弄这几天,但到目前为止我没有尝试过的任何事情都做得很好。

例如,https://serverfault.com/questions/171095/how-do-i-join-two-named-pipes-into-single-input-stream-in-linux处有一个有用的帖子,建议做这样的事情:

mkfifo alt_in
(tail -f alt_in & cat) | bash

这几乎正是我正在寻找的,除非你尝试使用退格键或箭头键,它不能正常工作。 (我想这是因为cat拦截击键,通常由bash中的readline库处理?)有人有其他建议吗?

最终,我想有一种方法来启动MATLAB过程,以便我可以从TextMate向它发送命令,但也可以在终端中与它进行交互。我使用MATLAB进行工作,但不是它的GUI或编辑器的忠实粉丝。

编辑2010年12月19日

感谢所有非常有用的建议!我想对任何有兴趣的人总结一下这个结果。我查看了rlwrap,但由于我的目标是让任何人都可以使用的TextMate包中的这个工作,我对依赖非标准实用程序(我应该首先提到)非常犹豫。我还简要地查看了expectunbuffer,但是,它们看起来相当复杂,我只是没有勇气深入研究它。

screen工作得很好 - 如下所示,我可以打开终端,启动screen,启动matlab -nodesktop,然后就可以发送TextMate,例如发送在TextMate命令中使用screen -X ...将所选文本添加到Matlab。我注意到这种方法的缺点是:

  1. 发送超过1,024个字符的文本块导致“screen”出错;我认为某处有一些缓冲区不能容纳更多,但没有花时间试图追踪它。
  2. Screen有自己的回滚缓冲区,使得Terminal的滚动条毫无用处。也许可以选择改变它的工作方式?
  3. Control-A是`screen`的命令按键;除非重新绑定命令键,否则不能使用它移动到行的开头。

当我在玩screen时,我想到虽然我问过的问题是关于连接管道和STDIN等等,但实际上我只关心这个问题是一个非常具体的案例:从中获取文本TextMate到终端。这促使我尝试用AppleScript做到这一点,令人惊讶的是,结果比我试过的任何其他东西更简单,更强大。创建一个TextMate命令,将选定的文本或当前行作为输入,并包含

#!/usr/bin/env osascript

set input_command to do shell script "cat"

tell application "Terminal"
    do script input_command in window 1
end tell

只要MATLAB位于最前面的终端窗口,这就很有效。 (也可以搜索运行MATLAB的终端选项卡,为了清楚起见,我将其排除在外。)

这个故事的寓意是我应该提出更具体的问题。再次感谢所有的帮助;我从摔跤中学到了很多东西!

3 个答案:

答案 0 :(得分:1)

尝试通过unbuffer管道化数据。

答案 1 :(得分:1)

尝试一下:

mkfifo alt_in
(tail -f alt_in & rlwrap cat) | bash

您将不会收到提示,但您可以输入命令并使用箭头键等,包括历史记录检索。您可以echo从另一个终端命令进入命名管道,它们将在接收端执行,但它们不会在其历史记录中。

其他一些需要调查的事项:

  • 期望
  • screen -x和screen -X

对于后者,在一个终端开始screen。你可以像往常那样与Bash进行交互。现在在另一个终端上,做

screen -ls

确定您开始的screen会话的PID。它将是一行开头的数字,如下所示:

31544.pts-2.hostname     (01/01/2010 01:01:01 PM)        (Attached)

现在你可以这样做:

screen -S 31544 -X stuff $'echo Your ad here.\n'

将导致echo命令在另一个终端上执行。 $''导致转义内的转义序列被解释,在这种情况下为我们提供换行符,因此我们可以“按” Enter

假设我们这样做了:

screen -S 31544 -X stuff $'top\n'

现在top正在运行。我们可以去那个终点站并按 q 退出,但那里的乐趣在哪里?

screen -S 31544 -X stuff 'q'

请注意,这次我们不需要换行符。

答案 2 :(得分:0)

键盘输入有不同的风格,称为“原始模式”,“cbreak模式”和“熟食模式”。

原始模式是操作系统在您向程序输入时传递每次击键的地方(例如bash)。

熟化模式是操作系统缓冲一行并允许您进行简单编辑(如删除字符)的位置。当你按RETURN或EOF(通常是 Ctrl-D )时,它会向程序发送一行。

stty命令允许您定义一些解释为行尾(RETURN),EOF(Ctrl-D)和其他一些键码的键码。

Cbreak-mode是一个中途,其中许多控制字符保留其常用功能,但操作系统仍然一次向应用程序发送一个字符。像bash,vi和less这样的程序通常使用这种模式。

如果您将终端设置为原始模式,那么除非您正在运行的程序合作,否则您无法再使用键盘“突破”它。

期望(herehere)可以为Bash提供一个终端界面,这样它仍然认为它是从普通键盘运行的,并且仍然会执行所有酷bash命令行编辑,我们'习惯了。

Expect可以在原始模式和管道中读取键盘输入并无缝传递。