我试图理解Python的子进程模块是如何工作的,并且已经开始为自己设置一些并不像我想象的那么简单的问题。具体来说,我正在尝试与已创建为子进程的 Python 智能交互器进行交互。
我创建了一个测试模块,其结构dummy.py
如下:
def hi():
print "Hi Earth"
hi()
然后,为了测试我使用子流程模块的能力,我编写了一个名为 pyrun.py
的模块,其结构如下:
import subprocess
def subprocess_cmd1():
outFile = open("tempy1.tmp",'w')
proc = subprocess.Popen("pwd", stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True)
outFile.close()
def subprocess_cmd2():
outFile = open("tempy2.tmp",'w')
proc = subprocess.Popen('python dummy.py', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True)
outFile.close()
def subprocess_cmd3():
outFile = open("tempy3.tmp",'w')
proc = subprocess.Popen('python', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True)
proc.communicate('import dummy')
outFile.close()
def subprocess_cmd4():
outFile = open("tempy4.tmp",'w')
proc = subprocess.Popen('python', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True)
proc.communicate('import dummy')
proc.communicate('dummy.hi()')
outFile.close()
print "Start"
subprocess_cmd1()
subprocess_cmd2()
subprocess_cmd3()
subprocess_cmd4()
print "Stop"
这个想法是从调用进程向子进程发送输入,并将所有输出发送到文本文件。
当我尝试从命令行运行pyrun时,我得到以下结果:
me@Bedrock1:~/Projects/LushProjects/newCode$ python pyrun.py
Start
Traceback (most recent call last):
File "pyrun.py", line 42, in <module>
subprocess_cmd4()
File "pyrun.py", line 35, in subprocess_cmd4
proc.communicate('dummy.hi()')
File "/usr/lib/python2.7/subprocess.py", line 785, in communicate
self.stdin.write(input)
ValueError: I/O operation on closed file
subprocess_cmd1 - 3
运行而不会崩溃。尝试执行语句时,错误出现在 subprocess_cmd4()
中:
proc.communicate('dummy.hi()')
这似乎是因为communicate
方法在首次使用管道后关闭管道以stdin
。它为什么要这样做?假设管道应该关闭有什么好处吗?
此外,当我查看tempy3.tmp
的内容(我的subprocess_cmd3
输出文件(时,它缺少 Python 解释器的"开始"文本 - 即
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
为什么?我将stdout
和stderr
重定向到outFile
。
最后,为什么tempy4.tmp
完全是空的?它不应该至少包含崩溃之前发送给它的文本吗?(即它看起来很像tempy3.tmp
(
定义你的解释器:
interpreter=sys.executable
并将列表作为第一个参数传递:
fproc=subprocess.Popen([interpreter,script,'-f',datafile], stdout=subprocess.PIPE)
问题是你如何使用 subprocess.communicate()
,它需要一个字符串。从文档中
https://docs.python.org/2/library/subprocess.html
与进程交互:将数据发送到标准。从标准输出读取数据,并 stderr,直到到达文件末尾。等待进程终止。 可选的输入参数应该是要发送给子级的字符串 进程,或无,如果不应向子级发送任何数据。
试试这个:
def subprocess_cmd4():
outFile = open("tempy4.tmp",'w')
proc = subprocess.Popen('python', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True)
proc.communicate('import dummyndummy.hi()n')
outFile.close()
回答您关于communicate()
的问题。
communicate()
只能使用一次,因为被调用outFile
在第一次通信后已关闭。再次调用 communicate()
永远不会产生任何内容,因为您已经读取了上一个输出中的所有输出。使用它的一个优点是,您无需在使用它后终止。
回答您关于python
命令的标头在tempy3.py
中的位置的问题。
这只是python的标头,而不是"问题"的"答案"。你只是进入了python模式,并没有要求任何回报。但是,如果您尝试:
proc.communicate('1+1')
然后应该将2
写入文件 tempy4.tmp,对吧?
没有。这是因为communicate()
只能从Unix命令行获取输出,而不能从python获取输出。例如
proc = subprocess.Popen('ls', stdin=subprocess.PIPE, stdout=outFile, stderr=outFile, shell=True)
proc.communicate('-l')
输出:
student@ubuntu:~/Desktop/Testing$ pg tempy4.tmp
dummy.py
dummy.pyc
pyrun.py
tempy1.tmp
tempy2.tmp
tempy3.tmp
tempy4.tmp
我按原样运行了您的程序,tempy4.tmp
实际上显示Hi Earth
一次,并且具有与您相同的错误。但是,如果您摆脱了第二个communicate()
并且只有一个,则可以按照@user590028指出的那样进行操作:
proc.communicate('import dummyndummy.hi()n')
但是,子进程不是将所有命令集中在一行中,而是允许您使用以下stdin.write
执行此操作:
proc.stdin.write('import dummyn')
proc.communicate('dummy.hi()')
*确保在命令后放置n
新行。它们都输出:
Hi Earth
Hi Earth