요약 (또는 "tl; dr"버전) : 최대 하나만 있으면 쉽게 수행 할 수 있습니다 subprocess.PIPE
. 그렇지 않으면 어렵습니다.
subprocess.Popen
그 일을 어떻게하는지에 대해 조금 설명해야 할 때 입니다.
(주의 : 이것은 3.x와 비슷하지만 Python 2.x 용입니다 .Windows 변형에 대해서는 매우 모호합니다. POSIX를 훨씬 잘 이해합니다.)
이 Popen
기능은 0 ~ 3 개의 I / O 스트림을 동시에 처리해야합니다. 이러한 표시된다 stdin
, stdout
그리고, stderr
평소와 같이.
다음을 제공 할 수 있습니다.
None
스트림을 리디렉션하고 싶지 않음을 나타냅니다. 대신 평상시와 같이 상속합니다. POSIX 시스템에서 이것은 최소한 sys.stdout
파이썬의 실제 표준 출력 인 파이썬을 사용한다는 의미는 아닙니다 . 마지막 데모를 참조하십시오.
int
값. 이것은 "raw"파일 디스크립터입니다 (최소한 POSIX). (사이드 노트 : PIPE
그리고 STDOUT
실제로 int
. 내부이야,하지만있다 "불가능"기술자, -1과 -2)
- 스트림 — 실제로
fileno
메소드 가있는 모든 객체 . Popen
를 사용하여 해당 스트림에 대한 설명자를 찾은 stream.fileno()
다음 int
값으로 진행 합니다.
subprocess.PIPE
, 파이썬이 파이프를 만들어야 함을 나타냅니다.
subprocess.STDOUT
( stderr
만 해당) : Python에게 for와 동일한 설명자를 사용하도록 지시하십시오 stdout
. 에 대해 (비 None
) 값을 제공 한 경우에만 의미가 stdout
있으며, 설정 한 경우 에만 필요 합니다 stdout=subprocess.PIPE
. (그렇지 않으면에 제공 한 것과 동일한 인수를 제공 할 수 있습니다 ( stdout
예 :) Popen(..., stdout=stream, stderr=stream)
)
가장 쉬운 경우 (파이프 없음)
아무것도 리디렉션하지 않으면 (세 가지 모두 기본값으로 None
두거나 explicit을 명시하십시오 None
) Pipe
매우 쉽습니다. 하위 프로세스를 분리하고 실행하면됩니다. 당신이 비에 리디렉션 경우 또는 PIPE
-an int
또는 스트림의 fileno()
OS가 모든 작업을 수행으로 - 그것은이 쉬운 아직. 파이썬은 stdin, stdout 및 / 또는 stderr을 제공된 파일 설명자에 연결하여 하위 프로세스를 분리하기 만하면됩니다.
여전히 쉬운 케이스 : 하나의 파이프
하나의 스트림 만 리디렉션해도 Pipe
여전히 쉬운 일이 있습니다. 한 번에 하나의 스트림을 선택하고 시청합시다.
당신은 몇 가지를 제공한다고 가정 stdin
하지만,하자 stdout
및 stderr
취소 리디렉션 이동하거나 파일 기술자로 이동합니다. 부모 프로세스로서, 파이썬 프로그램은 단순히 write()
파이프로 데이터를 보내는 데 사용 하면됩니다. 이를 직접 수행 할 수 있습니다 (예 :
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
proc.stdin.write('here, have some data\n') # etc
또는 당신의 표준 입력 데이터를 전달할 수 있습니다 proc.communicate()
후 않으며, stdin.write
위에 표시합니다. 출력이 나오지 않으므로 communicate()
다른 실제 작업이 하나만 있습니다. 파이프를 닫습니다. 호출하지 않으면 하위 프로세스가 더 이상 데이터가 전달되지 않음을 알 수 있도록 파이프를 닫으 proc.communicate()
려면 호출해야합니다 proc.stdin.close()
.
당신이 캡처한다고 가정 stdout
하지만, 휴가 stdin
및 stderr
혼자. 다시 말하지만, 더 쉽습니다. proc.stdout.read()
더 이상 출력이 없을 때까지 호출하십시오 . 이후 proc.stdout()
정상적인 파이썬 I입니다 / O 당신처럼, 그것은 모든 정상적인 구조를 사용할 수 있습니다 스트리밍 :
for line in proc.stdout:
또는 다시 사용할 수 있습니다 proc.communicate()
. 간단히 사용할 수 read()
있습니다.
캡처 만하려면와 stderr
동일하게 작동합니다 stdout
.
일이 힘들어지기 전에 한 가지 더 트릭이 있습니다. 캡처 할 가정 stdout
, 또한 캡처 stderr
하지만, 표준 출력과 같은 파이프 :
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
이 경우 subprocess
"속임수"! 글쎄,이 작업을 수행해야하므로 실제로 속임수가 아닙니다 .stdout과 stderr이 부모 (Python) 프로세스로 피드백되는 (단일) 파이프 디스크립터로 지정된 하위 프로세스를 시작하여 하위 프로세스를 시작합니다. 부모 측에는 출력을 읽는 데 필요한 단일 파이프 설명 자만 있습니다. 모든 "stderr"출력 이에 나타나고을 proc.stdout
호출 proc.communicate()
하면 stderr 결과 (튜플의 두 번째 값)는 None
문자열이 아닙니다.
어려운 경우 : 두 개 이상의 파이프
둘 이상의 파이프를 사용하려고 할 때 문제가 발생합니다. 실제로 subprocess
코드 자체에는 다음과 같은 비트가 있습니다.
def communicate(self, input=None):
...
# Optimization: If we are only using one pipe, or no pipe at
# all, using select() or threads is unnecessary.
if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
그러나 아아, 여기서 우리는 적어도 두 개, 아마도 세 개의 다른 파이프를 만들었으므로 count(None)
1 또는 0을 반환합니다. 우리는 어려운 일을해야합니다.
Windows에서 이는 및 에 threading.Thread
대한 결과를 누적 하는 데 사용 되며 상위 스레드가 입력 데이터를 전달한 다음 파이프를 닫습니다.self.stdout
self.stderr
self.stdin
POSIX에서, poll
가능하다면 select
출력을 축적하고 표준 입력을 전달하기 위해 사용합니다. 이 모든 것은 (단일) 부모 프로세스 / 스레드에서 실행됩니다.
교착 상태를 피하려면 스레드 또는 폴링 / 선택이 필요합니다. 예를 들어, 우리가 세 개의 스트림을 모두 세 개의 개별 파이프로 리디렉션했다고 가정합니다. 또한 쓰기 프로세스가 일시 중단되기 전에 파이프에 채워질 수있는 데이터의 양에 약간의 제한이 있고, 읽기 프로세스가 다른 쪽 끝에서 파이프를 "정리"할 때까지 기다린다고 가정하십시오. 설명을 위해 작은 제한을 단일 바이트로 설정해 봅시다. (제한이 1 바이트보다 훨씬 크다는 것을 제외하고는 실제로 작동 방식입니다.)
부모 (Python) 프로세스가 여러 바이트를 쓰려고 하면 ( 예 : 'go\n'
to proc.stdin
) 첫 번째 바이트가 들어가고 두 번째 바이트는 Python 프로세스가 일시 중단되어 하위 프로세스가 첫 번째 바이트를 읽을 때까지 기다리면서 파이프를 비 웁니다.
한편, 서브 프로세스가 친숙한 "Hello! Do n't Panic!"을 인쇄하기로 결정했다고 가정하십시오. 인사. 는 H
자사의 표준 출력 파이프로 전환하지만은 e
부모가 읽어 기다리고, 일시 중단을 야기 H
표준 출력 파이프를 비우는.
이제 우리는 멈췄습니다. 파이썬 프로세스는 잠 들어 "go"라고 말하기를 기다리고 있으며, 서브 프로세스는 잠 들어 있습니다. "Hello! Do n't Panic!"
subprocess.Popen
코드 스레딩 또는-선택 / 설문 조사와 함께이 문제를 피할 수 있습니다. 바이트가 파이프를 통과 할 수 있으면 바이트가 이동합니다. 그들이 할 수 없을 때, 전체 프로세스가 아닌 스레드 만이 잠자기해야한다. 또는 선택 / 폴링의 경우, 파이썬 프로세스는 동시에 "쓰기 가능"또는 "사용 가능한 데이터"를 기다리는 동안 프로세스의 표준 입력에 쓴다 공간이있을 때만 데이터가 준비된 경우에만 stdout 및 / 또는 stderr을 읽습니다. proc.communicate()
코드 (실제로 _communicate
털이 사건을 취급하는 곳)가 반환 모든 표준 입력 데이터를 한 번에 (있는 경우) 전송 된 모든 표준 출력 및 / 또는 표준 오류 데이터가 축적되어있다.
리디렉션에 관계없이 두 개의 다른 파이프 stdout
와 stderr
두 개의 파이프를 모두 읽으려면 stdin
교착 상태도 피해야합니다. 여기서 교착 상태 시나리오는 다릅니다. 하위 프로세스 stderr
에서 데이터를 가져 오는 stdout
동안 또는 그 반대로 데이터를 오래 쓸 때 발생 하지만 여전히 존재합니다.
데모
나는 리디렉션되지 않은 Python subprocess
es가 기본 stdout에 쓰지 않는다는 것을 보여 주겠다고 약속했습니다 sys.stdout
. 다음은 몇 가지 코드입니다.
from cStringIO import StringIO
import os
import subprocess
import sys
def show1():
print 'start show1'
save = sys.stdout
sys.stdout = StringIO()
print 'sys.stdout being buffered'
proc = subprocess.Popen(['echo', 'hello'])
proc.wait()
in_stdout = sys.stdout.getvalue()
sys.stdout = save
print 'in buffer:', in_stdout
def show2():
print 'start show2'
save = sys.stdout
sys.stdout = open(os.devnull, 'w')
print 'after redirect sys.stdout'
proc = subprocess.Popen(['echo', 'hello'])
proc.wait()
sys.stdout = save
show1()
show2()
실행할 때 :
$ python out.py
start show1
hello
in buffer: sys.stdout being buffered
start show2
hello
당신이 추가하면 첫 번째 루틴이 실패하지 않습니다 stdout=sys.stdout
A와, StringIO
오브젝트가있다 fileno
. 두 번째 는로 리디렉션 된 이후 hello
추가 한 경우를 생략합니다 .stdout=sys.stdout
sys.stdout
os.devnull
(Python의 파일 디스크립터 -1 을 리디렉션 하면 하위 프로세스 가 해당 리디렉션 을 따릅니다. open(os.devnull, 'w')
호출은 fileno()
2보다 큰 스트림을 생성합니다 .)
Popen.poll
에서처럼 사용할 수 있습니다 .