program tip

subprocess.communicate ()에서 스트리밍 입력 읽기

radiobox 2020. 10. 23. 07:45
반응형

subprocess.communicate ()에서 스트리밍 입력 읽기


subprocess.communicate()약 1 분 동안 실행되는 프로세스에서 표준 출력을 읽기 위해 Python을 사용 하고 있습니다.

해당 프로세스의 각 줄을 stdout스트리밍 방식으로 인쇄하여 생성 된 출력을 볼 수 있지만 계속하기 전에 프로세스가 종료되는 것을 차단하려면 어떻게해야합니까?

subprocess.communicate() 한 번에 모든 출력을 제공하는 것처럼 보입니다.


내가 생각하는주의 사항 (아래) JF 세바스찬의 방법은 더 좋다.


다음은 오류를 확인하지 않는 간단한 예입니다.

import subprocess
proc = subprocess.Popen('ls',
                       shell=True,
                       stdout=subprocess.PIPE,
                       )
while proc.poll() is None:
    output = proc.stdout.readline()
    print output,

경우 ls모든 데이터를 읽은 전에 끝이 너무 빨리, 그 동안 루프가 종료 될 수 있습니다.

다음과 같이 stdout에서 나머지를 잡을 수 있습니다.

output = proc.communicate()[0]
print output,

하위 프로세스가 stdout 버퍼를 플러시하자마자 하위 프로세스의 출력을 한 줄씩 가져 오려면 :

#!/usr/bin/env python2
from subprocess import Popen, PIPE

p = Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1)
with p.stdout:
    for line in iter(p.stdout.readline, b''):
        print line,
p.wait() # wait for the subprocess to exit

iter()Python 2의 미리 읽기 버그 를 해결 하기 위해 작성되는 즉시 행을 읽는 데 사용됩니다 .

하위 프로세스의 stdout이 비대화 형 모드에서 라인 버퍼링 대신 블록 버퍼링을 사용하는 경우 (이로 인해 자식의 버퍼가 가득 차거나 자식이 명시 적으로 플러시 할 때까지 출력이 지연됨) 다음을 사용하여 버퍼링되지 않은 출력을 강제로 시도 할 수 있습니다. pexpect, pty모듈 또는 unbuffer, stdbuf, script유틸리티 , 참조 왜 그냥 파이프 사용 (는 popen을 ()) : Q는?


다음은 Python 3 코드입니다.

#!/usr/bin/env python3
from subprocess import Popen, PIPE

with Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1,
           universal_newlines=True) as p:
    for line in p.stdout:
        print(line, end='')

참고 : 하위 프로세스의 바이트 문자열을있는 그대로 출력하는 Python 2와 달리; Python 3은 텍스트 모드를 사용합니다 (cmd의 출력은 locale.getpreferredencoding(False)인코딩을 사용하여 디코딩 됨 ).


스트리밍 방식으로 프로세스에서 출력을 수집하는 가장 간단한 방법은 다음과 같습니다.

import sys
from subprocess import *
proc = Popen('ls', shell=True, stdout=PIPE)
while True:
    data = proc.stdout.readline()   # Alternatively proc.stdout.read(1024)
    if len(data) == 0:
        break
    sys.stdout.write(data)   # sys.stdout.buffer.write(data) on Python 3.x

readline()또는 read()읽을 수있는 것도이 (가없는 경우 그렇지 않은 경우는 차단 - 기능은 프로세스가 종료 된 후, EOF에 빈 문자열을 반환해야합니다 readline(), 줄 바꿈을 포함하므로 빈 줄에, 그것은 반환 "\ n"). 이렇게하면 communicate()루프 후 어색한 최종 호출 이 필요하지 않습니다 .

read()매우 긴 파일에서는 최대 메모리 사용량을 줄이는 것이 바람직 할 수 있습니다. 전달 된 수는 임의적이지만이를 제외하면 전체 파이프 출력을 한 번에 읽는 것이 바람직하지 않을 수 있습니다.


비 차단 접근 방식을 원하면 process.communicate(). subprocess.Popen()인수 stdout를로 설정하면 PIPE에서 읽고 process.stdout프로세스가 여전히을 사용하여 실행되는지 확인할 수 있습니다 process.poll().


If you're simply trying to pass the output through in realtime, it's hard to get simpler than this:

import subprocess

# This will raise a CalledProcessError if the program return a nonzero code.
# You can use call() instead if you don't care about that case.
subprocess.check_call(['ls', '-l'])

See the docs for subprocess.check_call().

If you need to process the output, sure, loop on it. But if you don't, just keep it simple.

Edit: J.F. Sebastian points out both that the defaults for the stdout and stderr parameters pass through to sys.stdout and sys.stderr, and that this will fail if sys.stdout and sys.stderr have been replaced (say, for capturing output in tests).


myCommand="ls -l"
cmd=myCommand.split()
# "universal newline support" This will cause to interpret \n, \r\n and \r     equally, each as a newline.
p = subprocess.Popen(cmd, stderr=subprocess.PIPE, universal_newlines=True)
while True:    
    print(p.stderr.readline().rstrip('\r\n'))

참고URL : https://stackoverflow.com/questions/2715847/read-streaming-input-from-subprocess-communicate

반응형