[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)
따라서와 같은 프로세스를 시작 Process.execute("mvn clean install")
하면 프로세스가 완료 될 때까지 프로그램이 대기하고 프로그램의 전체 출력을 얻습니다. 완료하는 데 시간이 걸리는 프로세스를 실행하는 경우 짜증이납니다.
루프 또는 무언가가 끝나기 전에 프로세스 출력을 폴링하여 프로그램이 한 줄씩 프로세스 출력을 작성할 수 있습니까?
** [편집] 죄송합니다.이 질문을 게시하기 전에 검색이 잘되지 않았습니다. 스레딩이 실제로 핵심입니다. 방법을 보여주는 예제를 여기에서 찾았습니다 : **
Python Subprocess. 스레드에서 열기
답변
명령이 출력하는 즉시 iter 를 사용 하여 행을 처리 할 수 있습니다 lines = iter(fd.readline, "")
. 다음은 일반적인 사용 사례를 보여주는 전체 예입니다 (도움을 주신 @jfs 덕분에).
from __future__ import print_function # Only Python 2.x
import subprocess
def execute(cmd):
popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True)
for stdout_line in iter(popen.stdout.readline, ""):
yield stdout_line
popen.stdout.close()
return_code = popen.wait()
if return_code:
raise subprocess.CalledProcessError(return_code, cmd)
# Example
for path in execute(["locate", "a"]):
print(path, end="")
답변
좋아, 나는이 질문에서 조각을 사용하여 (어떤 제안 스레드를 사용하는 이유는 더 나은 감사합니다 것) 스레드없이 그것을 해결하기 위해 관리 가 실행되는 동안 서브 프로세스의 표준 출력을 가로 채기를
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)
답변
파이썬 3에서 stdout 버퍼가 플러시되는 즉시 서브 프로세스의 출력을 라인별로 인쇄하려면 :
from subprocess import Popen, PIPE, CalledProcessError
with Popen(cmd, stdout=PIPE, bufsize=1, universal_newlines=True) as p:
for line in p.stdout:
print(line, end='') # process line here
if p.returncode != 0:
raise CalledProcessError(p.returncode, p.args)
주의 : 필요하지 않습니다 p.poll()
. eof에 도달하면 루프가 종료됩니다. 그리고 당신은 필요하지 않습니다iter(p.stdout.readline, '')
– 미리 읽기 버그는 파이썬 3에서 해결되었습니다.
Python : subprocess.communicate ()에서 스트리밍 입력 읽기를 참조하십시오 .
답변
실제로 출력 을 인쇄 하고 싶을 때 이렇게하는 간단한 방법이 있습니다 .
import subprocess
import sys
def execute(command):
subprocess.check_call(command, stdout=sys.stdout, stderr=subprocess.STDOUT)
여기서 우리는 단순히 하위 프로세스를 자체 stdout을 가리키고 기존 성공 또는 예외 API를 사용합니다.
답변
@tokland
코드를 시도하고 3.4로 수정했으며 Windows dir.cmd는 cmd-file로 저장된 간단한 dir 명령입니다.
import subprocess
c = "dir.cmd"
def execute(command):
popen = subprocess.Popen(command, stdout=subprocess.PIPE,bufsize=1)
lines_iterator = iter(popen.stdout.readline, b"")
while popen.poll() is None:
for line in lines_iterator:
nline = line.rstrip()
print(nline.decode("latin"), end = "\r\n",flush =True) # yield line
execute(c)
답변
누군가가 두에서 읽고 싶은 경우 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()
시킵니다.
답변
파이썬 스크립트에서 stdout을 얻기 위해이 질문에 대한 답변을 시도하는 사람은 Python이 stdout을 버퍼링하므로 stdout을 보는 데 시간이 걸릴 수 있습니다.
대상 스크립트에서 각 stdout 쓰기 후에 다음을 추가하여이를 수정할 수 있습니다.
sys.stdout.flush()