目前,我有这样的事情:
self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE)
out, err = self.process.communicate()
我正在运行的命令对输出进行流式处理,我需要在继续之前阻止该进程。
如何制作它以便我可以捕获流输出并通过标准输出打印流输出?当我设置stdout=subprocess.PIPE
时,我可以捕获输出,但不会打印输出。如果我遗漏stdout=subprocess.PIPE
,则会打印输出,但communicate()
将返回None
。
是否有一个解决方案可以满足我的要求WHILE提供阻塞,直到流程终止/完成并避免缓冲区问题和管道死锁问题提到here?
谢谢!
答案 0 :(得分:4)
我可以想到一些解决方案。
#1:你可以直接进入源代码来抓取the code for communicate
,复制并粘贴它,添加代码,打印出来的每一行以及缓冲内容。 (如果你自己的stdout
因为一个死锁的父母而被阻止,你可以使用threading.Queue
或者其他东西。)这显然有些笨拙,但这很容易,而且会安全的。
但实际上,communicate
很复杂,因为它需要完全通用,并处理你没有的情况。这里你需要的只是中心技巧:在问题上抛出线程。
这样的事情:
self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE)
lines = []
def reader():
for line in self.process.stdout:
lines.append(line)
sys.stdout.write(line)
t = threading.Thread(target=reader)
t.start()
self.process.wait()
t.join()
您可能需要在reader
主题中进行一些错误处理。而且我不是100%确定你可以在这里安全地使用readline
。但这可能会起作用,也可能会接近。
#2:或者你可以创建一个包装器类,每当有stdout
个人stderr
时,它就会将文件对象和tees带到read
/ PIPE
。然后手动创建管道,并传入包裹的管道,而不是使用自动Queue
。这与#1完全相同(意味着没有问题,或者如果sys.stdout.write
可以阻止,则需要使用class TeeReader(object):
def __init__(self, input_file, tee_file):
self.input_file = input_file
self.tee_file = tee_file
def read(self, size=-1):
ret = self.input_file.read(size)
if ret:
self.tee_file.write(ret)
return ret
或其他内容)。
这样的事情:
PIPE
换句话说,它包装了一个文件对象(或类似于一个文件对象的东西),并且就像一个文件对象。 (当您使用process.stdout
时,input_file
是Unix上的真实文件对象,但可能就像在Windows上一样。)您需要委派给communicate
的任何其他方法都可以可能是直接委派,没有任何额外的包装。要么尝试这个,看看AttributeException
获取__getattr__
的方法是什么,并明确地对这些方法进行编码,或者执行通常的twisted
技巧来委派所有内容。 PS,如果你担心这个“文件对象”的想法意味着磁盘存储,请在维基百科上阅读Everything is a file。
#3:最后,您可以在PyPI上获取一个“异步子进程”模块,或者包含在{{1}}或其他异步框架中并使用它。 (这使可能避免死锁问题,但它不是保证 - 你仍然必须确保正确地为管道提供服务。)
答案 1 :(得分:1)
输出转到您的调用进程,主要是从stdout
捕获self.cmd
,因此输出不会转到其他任何地方。
您需要做的是从父母那里打印出来。如果你想看到输出,请进行处理。