如何将Tab键发送到Python子进程的stdin?

2 投票
3 回答
3209 浏览
提问于 2025-04-17 13:56

背景: 我有一个Python的子进程,它连接到一个类似命令行的应用程序,这个应用程序使用readline库来处理输入,并且它有一个和bash一样的TAB补全功能。子进程是这样创建的:

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

一切运行得很好,除了TAB补全功能。每当我的Python程序向子进程发送TAB字符,'\t'时,我在标准输入中得到的是5个空格,而不是触发readline库的TAB补全功能。 :(

问题: 我应该向子进程的标准输入发送什么,才能触发它的TAB补全功能?换句话说,我该如何发送TAB ,而不是TAB 字符,如果这可能的话?

相关但未解答和偏离主题:

触发基于readline的Python批处理过程的TAB补全

3 个回答

1

根据isedev的回答,我对我的代码进行了如下修改:

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

感谢大家提供的好方案。希望这个例子能帮助到其他人。 :)

2

其实,发送一个制表符到管道里并不存在。管道只能接受一串串的比特,而如果制表符没有起作用,那可能就没有解决办法了。

有一个类似的项目叫做 pexpect。从它的 interact() 代码来看,我没有看到什么明显的地方让它能工作而你的不能。考虑到这一点,最可能的解释是 pexpect 实际上做了一些工作,让自己看起来像一个伪终端。也许你可以把它的代码用到你的项目里?

3

这个像命令行的应用可能在区分一个终端是否连接到标准输入(stdin)和是否有管道(pipe)连接到它。很多Unix工具就是这样做的,以优化它们的缓冲(行缓冲和块缓冲)。而像命令行的工具在处理批量输入(也就是通过管道输入)时,可能会关闭命令补全功能,以避免出现意外的结果。命令补全其实是一个需要终端输入的互动功能。

可以看看 pty 模块,试着用主从配对作为你子进程的管道。

撰写回答