subprocess.Popen()
Windows에서 rsync.exe 를 만들고 Python에서 stdout을 인쇄하고 싶습니다 .
내 코드는 작동하지만 파일 전송이 완료 될 때까지 진행 상황을 파악하지 못합니다! 각 파일의 진행 상황을 실시간으로 인쇄하고 싶습니다.
IO를 처리하는 것이 더 나을 것이라고 들었으므로 이제 Python 3.1을 사용하십시오.
import subprocess, time, os, sys
cmd = "rsync.exe -vaz -P source/ dest/"
p, line = True, 'start'
p = subprocess.Popen(cmd,
shell=True,
bufsize=64,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
for line in p.stdout:
print(">>> " + str(line.rstrip()))
p.stdout.flush()
답변
일부에 대한 엄지 손가락의 규칙 subprocess
.
- 사용 하지 마십시오
shell=True
. 프로그램을 호출하기 위해 불필요하게 추가 쉘 프로세스를 호출합니다. - 프로세스를 호출 할 때 인수는 목록으로 전달됩니다.
sys.argv
파이썬에서는 목록이고argv
C에서도 마찬가지입니다. 따라서 문자열이 아닌 하위 프로세스를 호출 하기 위해 목록 을 전달Popen
합니다. - 리디렉션하지 마십시오
stderr
A와PIPE
당신이 그것을 읽을하지 않을 때. - 글을 쓰지 않을
stdin
때 리디렉션하지 마십시오 .
예:
import subprocess, time, os, sys
cmd = ["rsync.exe", "-vaz", "-P", "source/" ,"dest/"]
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, b''):
print(">>> " + line.rstrip())
즉, rsync가 터미널 대신 파이프에 연결되어 있음을 감지하면 출력을 버퍼링 할 가능성이 있습니다. 이것이 기본 동작입니다. 파이프에 연결될 때 프로그램은 실시간 결과를 위해 명시 적으로 stdout을 플러시해야합니다. 그렇지 않으면 표준 C 라이브러리가 버퍼링됩니다.
이를 테스트하려면 대신 다음을 실행하십시오.
cmd = [sys.executable, 'test_out.py']
test_out.py
다음 내용 으로 파일을 만듭니다 .
import sys
import time
print ("Hello")
sys.stdout.flush()
time.sleep(10)
print ("World")
해당 하위 프로세스를 실행하면 “Hello”가 표시되고 “World”를 제공하기 전에 10 초 동안 기다려야합니다. 즉, 위의하지와 파이썬 코드를 발생하는 경우 rsync
, 그 수단 rsync
은 운이 그래서 자체가 출력을 버퍼링한다.
해결책은 pty
같은 것을 사용하여에 직접 연결 하는 것 pexpect
입니다.
답변
나는 이것이 오래된 주제라는 것을 알고 있지만 지금 해결책이 있습니다. –outbuf = L 옵션을 사용하여 rsync를 호출합니다. 예:
cmd=['rsync', '-arzv','--backup','--outbuf=L','source/','dest']
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, b''):
print '>>> {}'.format(line.rstrip())
답변
Linux에서는 버퍼링을 제거하는 것과 동일한 문제가있었습니다. 마지막으로 “stdbuf -o0″(또는 예상에서 버퍼링 해제)을 사용하여 PIPE 버퍼링을 제거했습니다.
proc = Popen(['stdbuf', '-o0'] + cmd, stdout=PIPE, stderr=PIPE)
stdout = proc.stdout
그런 다음 stdout에서 select.select를 사용할 수 있습니다.
참조 /unix/25372/
답변
사용 사례에 따라 하위 프로세스 자체에서 버퍼링을 비활성화 할 수도 있습니다.
하위 프로세스가 Python 프로세스 인 경우 호출 전에 다음을 수행 할 수 있습니다.
os.environ["PYTHONUNBUFFERED"] = "1"
또는 env
인수에 이것을 전달하십시오 Popen
.
그렇지 않고 Linux / Unix를 사용하는 경우 stdbuf
도구를 사용할 수 있습니다 . 예 :
cmd = ["stdbuf", "-oL"] + cmd
또는 기타 옵션 에 대해서는 여기 를 참조하십시오 stdbuf
.
답변
for line in p.stdout:
...
다음 줄 바꿈까지 항상 차단됩니다.
“실시간”동작의 경우 다음과 같이해야합니다.
while True:
inchar = p.stdout.read(1)
if inchar: #neither empty string nor None
print(str(inchar), end='') #or end=None to flush immediately
else:
print('') #flush for implicit line-buffering
break
while 루프는 자식 프로세스가 표준 출력을 닫거나 종료 할 때 남겨집니다.
read()/read(-1)
자식 프로세스가 표준 출력을 닫거나 종료 될 때까지 차단됩니다.
답변
당신의 문제는 :
for line in p.stdout:
print(">>> " + str(line.rstrip()))
p.stdout.flush()
반복자 자체에는 추가 버퍼링이 있습니다.
다음과 같이 시도하십시오.
while True:
line = p.stdout.readline()
if not line:
break
print line
답변
stdout으로 버퍼링되지 않은 상태로 파이프에 인쇄 할 수 없습니다 (표준 출력으로 인쇄하는 프로그램을 다시 작성할 수없는 경우), 그래서 여기 내 해결책이 있습니다 :
stdout을 버퍼링되지 않은 sterr로 리디렉션합니다. '<cmd> 1>&2'
해야합니다. 다음과 같이 프로세스를 엽니 다. myproc = subprocess.Popen('<cmd> 1>&2', stderr=subprocess.PIPE)
stdout 또는 stderr과 구별 할 수 없지만 모든 출력이 즉시 표시됩니다.
이것이이 문제를 해결하는 데 도움이되기를 바랍니다.