通过STDIN/STDOUT使用Python启动和控制外部进程

7 投票
2 回答
7045 浏览
提问于 2025-04-15 12:42

我需要启动一个外部程序,并通过发送和接收信息来控制它,这些信息通过标准输入(stdin)和标准输出(stdout)进行交流。使用subprocess.Popen我可以启动这个程序,但我无法通过stdin来控制它的执行,这正是我需要的。

我想完成的流程是:

  1. 启动外部程序
  2. 进行若干步骤的循环
    1. 通过向它的stdin写入换行符,告诉外部程序完成下一步处理
    2. 等待外部程序通过向它的stdout写入换行符来表示它已经完成了这一步
  3. 关闭外部程序的stdin,以表示执行已经完成。

到目前为止,我想出了以下内容:

process = subprocess.Popen([PathToProcess], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
for i in xrange(StepsToComplete):
    print "Forcing step # %s" % i
    process.communicate(input='\n')

当我运行上面的代码时,换行符('\n')没有传递给外部程序,我一直停留在第0步。代码在process.communicate()这里卡住了,无法继续。我是不是错误地使用了communicate()方法?

另外,我该如何实现“等待外部程序写入换行符”的功能呢?

2 个回答

0

你可以使用Twisted这个库,通过调用reactor.spawnProcessLineReceiver来实现。

9

使用 process.communicate(input='\n') 是不对的。如果你查看 Python 的文档,你会发现它是把你的字符串写入子进程的标准输入(stdin),然后读取子进程的所有输出,直到子进程结束。从 doc.python.org 的描述来看:

Popen.communicate(input=None) 与进程交互:发送数据到标准输入。读取标准输出和标准错误,直到文件结束。等待进程终止。可选的输入参数应该是一个要发送给子进程的字符串,或者是 None,如果不需要发送数据给子进程的话。

实际上,你应该只向子进程的标准输入写入数据。然后在你的循环中读取它。

更像是这样:

process=subprocess.Popen([PathToProcess],stdin=subprocess.PIPE,stdout=subprocess.PIPE);
for i in xrange(StepsToComplete):
    print "Forcing step # %s"%i
    process.stdin.write("\n")
    result=process.stdout.readline()

这样做的效果更接近你想要的。

撰写回答