【问题标题】:how to send tab-key to python subprocess's stdin如何将制表键发送到 python 子进程的标准输入
【发布时间】:2013-01-11 23:03:38
【问题描述】:

背景:我有一个 Python 子进程,它连接到一个类似 shell 的应用程序,它使用 readline 库来处理输入,并且该应用程序有一个用于命令输入的 TAB 完成例程,就像重击。生成子进程,如下所示:

def get_cli_subprocess_handle():
    return subprocess.Popen(
                            '/bin/myshell',
                            shell=False,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT,
                            )

一切都很好,除了制表符完成。每当我的 Python 程序将制表符 '\t' 传递给子进程时,我会在 STDIN 中获得 5 个空格,而不是触发 readline 库的制表符完成例程。 :(

问题:我可以向子进程的 STDIN 发送什么来触发子进程的 tab-complete 功能?也许以另一种方式问:我如何发送 TAB key 而不是 TAB character,如果那是甚至可能?

相关但未得到答复和出轨:

trigger tab completion for python batch process built around readline

【问题讨论】:

  • 可能这不是一个答案(当然,不是足够的解决方案),但是,你为什么不检查输入是否是 5 个连续的空格?可能序列转义 \t 被您的 shell 捕获并转换为 5 个空格
  • @Manuel - 实际上,我自己通过 re.sub() 注入了'\t',所以我知道它不是 5 个空格。感谢您的仔细检查!

标签: python subprocess readline tab-completion


【解决方案1】:

类似 shell 的应用程序可能会区分连接到标准输入的终端和连接到它的管道。许多 Unix 实用程序这样做是为了优化它们的缓冲(行与块),并且类似 shell 的实用程序可能会禁用批处理输入(即 PIPE)的命令完成功能以避免意外结果。命令完成实际上是一个需要终端输入的交互式功能。

查看pty 模块并尝试使用主/从对作为子进程的管道。

【讨论】:

  • 谢谢,isedev!我通过 pty.openpty() 方法通过 masterPTY、slaveTTY 连接,然后我能够根据我的要求发送 tab 键。 ...我在下面添加了一个答案,详细说明了您的建议在我的案例中的应用。
【解决方案2】:

确实没有将标签 key 发送到管道这样的事情。管道只能接受位字符串,如果制表符不这样做,则可能没有解决方案。

有一个类似的项目叫做pexpect。只看它的interact() 代码,我没有看到任何明显的东西使它起作用而你的却没有。鉴于此,最可能的解释是 pexpect 实际上做了一些工作以使自己看起来像一个伪终端。也许您可以为此合并它的代码?

【讨论】:

  • 谢谢,肯! pexpect 项目确实很有帮助,您的解释是正确的。
【解决方案3】:

基于isedev's answer,我修改我的代码如下:

import os, pty

def get_cli_subprocess_handle():
    masterPTY, slaveTTY = pty.openpty()
    return masterPTY, slaveTTY, subprocess.Popen(
                                                 '/bin/myshell',
                                                 shell=False,
                                                 stdin=slaveTTY,
                                                 stdout=slaveTTY,
                                                 stderr=slaveTTY,
                                                 )

使用这个返回的元组,我能够根据需要执行select.select([masterPTY],[],[])os.read(masterPTY, 1024),并且我使用与pty 模块源中的私有方法非常相似的函数写入master-pty:

def write_all(masterPTY, data):
    """Successively write all of data into a file-descriptor."""
    while data:
        chars_written = os.write(masterPTY, data)
        data = data[chars_written:]
    return data

感谢大家提供好的解决方案。希望这个例子对其他人有所帮助。 :)

【讨论】:

    猜你喜欢
    • 2012-12-29
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 2022-07-08
    相关资源
    最近更新 更多