我想编写一个Python程序,能够与其他程序交互,即发送stdin并接收stdout数据。但我不能使用pexpect(尽管它的某些设计受到了启发)。我目前使用的过程如下:
- 附加一个pty到子进程的stdout
- 循环检查
subprocess.poll
,直到子进程退出- 当stdout中有数据可用时,立即将该数据写入当前stdout。
- 完成!
我已经原型化了一些代码(如下),虽然可以运行,但似乎有一个毛病一直困扰着我。在子进程完成后,如果不在调用select.select
时指定超时,父进程就会挂起。我真的不希望设置超时。这似乎有点不利于代码的优化。然而,我试图解决这个问题的所有其他方法都不起作用。Pexpect似乎通过使用os.execv
和pty.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不被缓冲。