我正在尝试编写一个能够与其他程序交互的 python 程序。这意味着发送标准输入和接收标准输出数据。我不能使用 pexpect(尽管它确实启发了一些设计)。我现在使用的过程是这样的:
- 将 pty 附加到子进程的标准输出
- 通过检查循环直到子进程退出
subprocess.poll
- 当标准输出中有可用数据时,立即将该数据写入当前标准输出。
- 结束!
我一直在对一些代码(如下)进行原型设计,这些代码有效,但似乎有一个让我烦恼的缺陷。子进程完成后,如果我在使用select.select
. 我真的不想设置超时。只是看起来有点脏。但是,我试图解决这个问题的所有其他方法似乎都不起作用。Pexpect 似乎通过使用os.execv
andpty.fork
而不是subprocess.Popen
和pty.openpty
我不喜欢的解决方案来解决它。我在检查子流程的生命周期方面做错了吗?我的方法不正确吗?
我正在使用的代码如下。我在 Mac OS X 10.6.8 上使用它,但我也需要它在 Ubuntu 12.04 上工作。
这是子流程运行器runner.py
:
import subprocess
import select
import pty
import os
import sys
def main():
master, slave = pty.openpty()
process = subprocess.Popen(['python', 'outputter.py'],
stdin=subprocess.PIPE,
stdout=slave, stderr=slave, close_fds=True)
while process.poll() is None:
# Just FYI timeout is the last argument to select.select
rlist, wlist, xlist = select.select([master], [], [])
for f in rlist:
output = os.read(f, 1000) # This is used because it doesn't block
sys.stdout.write(output)
sys.stdout.flush()
print "**ALL COMPLETED**"
if __name__ == '__main__':
main()
这是子流程代码outputter.py
。奇怪的随机部分只是为了模拟程序以随机间隔输出数据。如果您愿意,可以将其删除。没关系:
import time
import sys
import random
def main():
lines = ['hello', 'there', 'what', 'are', 'you', 'doing']
for line in lines:
sys.stdout.write(line + random.choice(['', '\n']))
sys.stdout.flush()
time.sleep(random.choice([1,2,3,4,5])/20.0)
sys.stdout.write("\ndone\n")
sys.stdout.flush()
if __name__ == '__main__':
main()
感谢您提供的任何帮助!
额外说明
使用 pty 是因为我想确保 stdout 不被缓冲。