subprocess.communicate()
약 1 분 동안 실행되는 프로세스에서 표준 출력을 읽기 위해 Python을 사용 하고 있습니다.
해당 프로세스의 각 줄을 stdout
스트리밍 방식으로 인쇄하여 생성 된 출력을 볼 수 있지만 계속하기 전에 프로세스가 종료되는 것을 차단하려면 어떻게해야합니까?
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,
while proc.poll() is None: time.sleep(0)
또는 그 효과와 관련이 있다고 생각합니다. 기본적으로 출력 줄 바꿈이 프로세스가 수행하는 마지막 작업인지 확인하거나 (통역사에게 다시 반복 할 시간을 줄 수 없기 때문에) "멋진"작업을 수행해야합니다.
하위 프로세스가 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)
인코딩을 사용하여 디코딩 됨 ).
b''
bytes
Python 2.7 및 Python 3 의 리터럴입니다.
bufsize=1
하면 차이를 만들 수 있습니다. 읽기만한다면 성능에만 차이가 있다고 말했듯이 그렇지 않은 경우이를 보여주는 최소한의 완전한 코드 예제를 제공 할 수 있습니까? p.stdin
pexpect
stderr=subprocess.STDOUT
하여 Popen()
). 여기에 링크 된 스레딩 또는 asyncio 솔루션 도 참조하십시오 .
stdout=PIPE
가 출력을 캡처하지 않으면 (여전히 화면에 표시됨) 프로그램이 stderr로 인쇄하거나 대신 터미널에 직접 인쇄 할 수 있습니다. stdout & stderr을 병합하려면 전달 stderr=subprocess.STDOUT
하십시오 (이전 설명 참조). tty에 직접 인쇄 된 출력을 캡처하려면 pexpect, pty 솔루션을 사용할 수 있습니다. . 다음은 더 복잡한 코드 예제 입니다.
스트리밍 방식으로 프로세스에서 출력을 수집하는 가장 간단한 방법은 다음과 같습니다.
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()
이 매우 긴 파일에서는 최대 메모리 사용량을 줄이는 것이 바람직 할 수 있습니다. 전달 된 수는 임의적이지만이를 제외하면 전체 파이프 출력을 한 번에 읽는 것이 바람직하지 않을 수 있습니다.
data = proc.stdout.read()
모든 데이터를 읽을 때까지 차단 됩니다. os.read(fd, maxsize)
(데이터를 사용할 수있는 즉시) 이전에 반환 할 수 있는 것과 혼동 될 수 있습니다 .
read()
제대로 작동 readline()
하며 최대 줄 길이가 합리적이면 마찬가지로 잘 작동합니다. 그에 따라 내 대답을 업데이트했습니다.
비 차단 방식을 원하면 process.communicate()
. subprocess.Popen()
인수 stdout
를로 설정하면 PIPE
에서 읽고 process.stdout
프로세스가 여전히을 사용하여 실행되는지 확인할 수 있습니다 process.poll()
.
단순히 실시간으로 출력을 전달하려는 경우 다음보다 더 간단하게하기가 어렵습니다.
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'])
subprocess.check_call ()에 대한 문서를 참조하십시오 .
출력을 처리해야하는 경우에는 루프를 실행하십시오. 그러나 그렇지 않다면 간단하게 유지하십시오.
편집 : JF Sebastian 은 stdout 및 stderr 매개 변수의 기본값이 sys.stdout 및 sys.stderr로 전달되고 sys.stdout 및 sys.stderr이 교체되면 실패한다고 지적합니다 (예 : 테스트).
sys.stdout
되거나 sys.stderr
대체 되면 작동하지 않습니다 . 경우 sys.stdout
, sys.stderr
다음 대체하지 않습니다 심지어는 간단하다 : subprocess.check_call(args)
.
call()
이상 check_call()
내가 원하는하지 않는 CalledProcessError
.
python -mthis
: "오류는 자동으로 전달되지 않아야합니다. 명시 적으로 침묵하지 않는 한." 왜 '즉 예제 코드 를 선호한다 check_call()
이상 call()
.
call()
은 끔찍하기 때문에 오류가 아닌 조건에서 0이 아닌 오류 코드를 반환합니다. 따라서 우리의 경우 0이 아닌 오류 코드는 실제로 오류가 아닙니다.
grep
오류가 없어도 0이 아닌 종료 상태를 반환 할 수 있는 프로그램 이 있습니다. 예외입니다. 기본적으로 0 종료 상태는 성공을 나타냅니다.
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'))
shlex.split(myCommand)
대신 사용을 고려해야 myCommand.split()
합니다. 인용 된 인수의 공백도 존중합니다.
몇 가지 작은 변경 사항으로 다른 python3 솔루션 추가 :
with
구성 을 사용하는 동안 종료 코드를 가져올 수 없습니다 ).import subprocess
import sys
def subcall_stream(cmd, fail_on_error=True):
# Run a shell command, streaming output to STDOUT in real time
# Expects a list style command, e.g. `["docker", "pull", "ubuntu"]`
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=1, universal_newlines=True)
for line in p.stdout:
sys.stdout.write(line)
p.wait()
exit_code = p.returncode
if exit_code != 0 and fail_on_error:
raise RuntimeError(f"Shell command failed with exit code {exit_code}. Command: `{cmd}`")
return(exit_code)