如何将Tab键发送到Python子进程的stdin?
背景: 我有一个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 字符,如果这可能的话?
相关但未解答和偏离主题:
3 个回答
根据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
感谢大家提供的好方案。希望这个例子能帮助到其他人。 :)
其实,发送一个制表符到管道里并不存在。管道只能接受一串串的比特,而如果制表符没有起作用,那可能就没有解决办法了。
有一个类似的项目叫做 pexpect。从它的 interact()
代码来看,我没有看到什么明显的地方让它能工作而你的不能。考虑到这一点,最可能的解释是 pexpect 实际上做了一些工作,让自己看起来像一个伪终端。也许你可以把它的代码用到你的项目里?
这个像命令行的应用可能在区分一个终端是否连接到标准输入(stdin)和是否有管道(pipe)连接到它。很多Unix工具就是这样做的,以优化它们的缓冲(行缓冲和块缓冲)。而像命令行的工具在处理批量输入(也就是通过管道输入)时,可能会关闭命令补全功能,以避免出现意外的结果。命令补全其实是一个需要终端输入的互动功能。
可以看看 pty
模块,试着用主从配对作为你子进程的管道。