要从我的python脚本启动程序,我使用以下方法:

def execute(command):
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    output = process.communicate()[0]
    exitCode = process.returncode

    if (exitCode == 0):
        return output
    else:
        raise ProcessException(command, exitCode, output)

所以当我启动一个进程,比如进程。执行("mvn clean install")时,我的程序会一直等待,直到进程完成,只有到那时我才能得到程序的完整输出。这是恼人的,如果我正在运行一个进程,需要一段时间才能完成。

我能让我的程序一行一行地写进程输出吗,在循环结束之前轮询进程输出什么的?

我找到了这篇文章,可能与此有关。


当前回答

如果有人想同时使用线程从stdout和stderr读取,这是我想到的:

import threading
import subprocess
import Queue

class AsyncLineReader(threading.Thread):
    def __init__(self, fd, outputQueue):
        threading.Thread.__init__(self)

        assert isinstance(outputQueue, Queue.Queue)
        assert callable(fd.readline)

        self.fd = fd
        self.outputQueue = outputQueue

    def run(self):
        map(self.outputQueue.put, iter(self.fd.readline, ''))

    def eof(self):
        return not self.is_alive() and self.outputQueue.empty()

    @classmethod
    def getForFd(cls, fd, start=True):
        queue = Queue.Queue()
        reader = cls(fd, queue)

        if start:
            reader.start()

        return reader, queue


process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdoutReader, stdoutQueue) = AsyncLineReader.getForFd(process.stdout)
(stderrReader, stderrQueue) = AsyncLineReader.getForFd(process.stderr)

# Keep checking queues until there is no more output.
while not stdoutReader.eof() or not stderrReader.eof():
   # Process all available lines from the stdout Queue.
   while not stdoutQueue.empty():
       line = stdoutQueue.get()
       print 'Received stdout: ' + repr(line)

       # Do stuff with stdout line.

   # Process all available lines from the stderr Queue.
   while not stderrQueue.empty():
       line = stderrQueue.get()
       print 'Received stderr: ' + repr(line)

       # Do stuff with stderr line.

   # Sleep for a short time to avoid excessive CPU use while waiting for data.
   sleep(0.05)

print "Waiting for async readers to finish..."
stdoutReader.join()
stderrReader.join()

# Close subprocess' file descriptors.
process.stdout.close()
process.stderr.close()

print "Waiting for process to exit..."
returnCode = process.wait()

if returnCode != 0:
   raise subprocess.CalledProcessError(returnCode, command)

我只是想分享这个,因为我在这个问题上试图做类似的事情,但没有一个答案能解决我的问题。希望它能帮助到某些人!

请注意,在我的用例中,外部进程杀死了Popen()所使用的进程。

其他回答

在Python 3.6中,我使用了这个:

import subprocess

cmd = "command"
output = subprocess.call(cmd, shell=True)
print(process)

简单比复杂好。

操作系统库内置模块系统。您应该执行代码并看到输出。

import os
os.system("python --version")
# Output
"""
Python 3.8.6
0
"""

在版本之后,它也打印返回值为0。

这个PoC不断地从进程中读取输出,并可以在需要时访问。只有最后一个结果被保留,所有其他输出都被丢弃,因此防止了PIPE的内存不足:

import subprocess
import time
import threading
import Queue


class FlushPipe(object):
    def __init__(self):
        self.command = ['python', './print_date.py']
        self.process = None
        self.process_output = Queue.LifoQueue(0)
        self.capture_output = threading.Thread(target=self.output_reader)

    def output_reader(self):
        for line in iter(self.process.stdout.readline, b''):
            self.process_output.put_nowait(line)

    def start_process(self):
        self.process = subprocess.Popen(self.command,
                                        stdout=subprocess.PIPE)
        self.capture_output.start()

    def get_output_for_processing(self):
        line = self.process_output.get()
        print ">>>" + line


if __name__ == "__main__":
    flush_pipe = FlushPipe()
    flush_pipe.start_process()

    now = time.time()
    while time.time() - now < 10:
        flush_pipe.get_output_for_processing()
        time.sleep(2.5)

    flush_pipe.capture_output.join(timeout=0.001)
    flush_pipe.process.kill()

print_date.py

#!/usr/bin/env python
import time

if __name__ == "__main__":
    while True:
        print str(time.time())
        time.sleep(0.01)

输出:你可以清楚地看到只有大约2.5s的输出间隔。

>>>1520535158.51
>>>1520535161.01
>>>1520535163.51
>>>1520535166.01

好吧,我设法解决它没有线程(任何建议,为什么使用线程会更好,感谢)使用从这个问题的一个片段拦截一个子进程的标准输出,而它正在运行

def execute(command):
    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    # Poll process for new output until finished
    while True:
        nextline = process.stdout.readline()
        if nextline == '' and process.poll() is not None:
            break
        sys.stdout.write(nextline)
        sys.stdout.flush()

    output = process.communicate()[0]
    exitCode = process.returncode

    if (exitCode == 0):
        return output
    else:
        raise ProcessException(command, exitCode, output)

对于试图回答这个问题并从Python脚本中获取标准输出的人来说,请注意Python会缓冲它的标准输出,因此可能需要一段时间才能看到标准输出。

这可以通过在目标脚本中的每个标准输出写入后添加以下内容来纠正:

sys.stdout.flush()