2017-01-04 2 views
0

저는 Gphoto2를 사용하여 DSLR에서 사진을 찍습니다. bash 명령을 기반으로 했으므로 subprocess.communicate을 사용하려했지만 카메라가 사진을 찍은 후에 멈 춥니 다.출력을 읽을 때 파이썬 하위 프로세스가 작동을 멈 춥니 다.

터미널에서 gphoto2 --capture-image-and-download을 시도하면 2 초 이내에 완료됩니다. 나는 라즈베리 파이를 만들고있어.

코드 :

import subprocess 

class Wrapper(object): 

    def __init__(self, subprocess): 
     self._subprocess = subprocess 

    def call(self,cmd): 
     p = self._subprocess.Popen(cmd, shell=True, stdout=self._subprocess.PIPE, stderr=self._subprocess.PIPE) 
     out, err = p.communicate() 
     return p.returncode, out.rstrip(), err.rstrip() 


class Gphoto(Wrapper): 
    def __init__(self, subprocess): 
     Wrapper.__init__(self,subprocess) 
     self._CMD = 'gphoto2' 

    def captureImageAndDownload(self): 
     code, out, err = self.call(self._CMD + " --capture-image-and-download") 
     if code != 0: 
      raise Exception(err) 
     filename = None 
     for line in out.split('\n'): 
      if line.startswith('Saving file as '): 
       filename = line.split('Saving file as ')[1] 
     return filename 


def main(): 
    camera = Gphoto(subprocess) 

    filename = camera.captureImageAndDownload() 
    print(filname) 

if __name__ == "__main__": 
    main() 

내가이 얻을 종료하면 :

Traceback (most recent call last): 
    File "test.py", line 39, in <module> 
    main() 
    File "test.py", line 35, in main 
    filename = camera.captureImageAndDownload() 
    File "test.py", line 22, in captureImageAndDownload 
    code, out, err = self.call(self._CMD + " --capture-image-and-download") 
    File "test.py", line 11, in call 
    out, err = p.communicate() 
    File "/usr/lib/python2.7/subprocess.py", line 799, in communicate 
    return self._communicate(input) 
    File "/usr/lib/python2.7/subprocess.py", line 1409, in _communicate 
    stdout, stderr = self._communicate_with_poll(input) 
    File "/usr/lib/python2.7/subprocess.py", line 1463, in _communicate_with_poll 
    ready = poller.poll() 
KeyboardInterrupt 

어떤 아이디어?

+1

견적 "표준 출력 및 표준 오류로부터 데이터를 읽기 (참고 당신에게 줄 수도 Python2 또는 3, p.stdout.read()을 사용하는 경우에 따라서는 등 대신 O = b''해야 O = '' 의미, 다시 데이터를 바이트) 파일에 도달했습니다. " - 프로세스가 종료되지 않은 경우 입력 대기 중입니다. 프로세스가 완료 되었습니까? – Torxed

+0

Im 확실합니다. 카메라의 셔터 소리가 들리고 파일이 생성됩니다. 일단 내가 적어도 5 분 동안 앉아 있지만 여전히 동결하자 ... 터미널에서 프로세스를 테스트하고 추가 입력없이 작동합니다. – Dennis

+0

대신 다음과 비슷한 것을 시도해보십시오 : https://gist.github.com/anonymous/0811f71ca0b290f2625c9ba768bd45fd – Torxed

답변

0

위의 의견을 바탕으로, 우리가 생각해 냈습니다. .communicate() 전화가 프로그램을 중단 시켰고, 실행 된 명령이 제대로 종료되지 않았기 때문에 많은 의문이 들었습니다.

이 문제를 해결하는 데 사용할 수있는 한 가지 방법은 완료되면 프로세스를 수동으로 폴링하고 진행 상황에 따라 출력을 인쇄하는 것입니다.
위의 요지는 전화로 작성되었으므로 제대로 사용하지는 않았지만 명령을 수동으로 폴링 할 때 출력을 잡는 데 사용할 수있는 예제 코드가 있습니다.

import subprocess 
from time import time 
class Wrapper(): 
    def call(self, cmd): 
     p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
     O = '' 
     E = '' 
     last = time() 
     while p.poll() is None: 
      if time() - last > 5: 
       print('Process is still running') 
       last = time() 
      tmp = p.stdout.read(1) 
      if tmp: 
       O += tmp 
      tmp = p.stderr.read(1) 
      if tmp: 
       E += tmp 
     ret = p.poll(), O+p.stdout.read(), E+p.stderr.read() # Catch remaining output 
     p.stdout.close() # Always close your file handles, or your OS might be pissed 
     p.stderr.close() 
     return ret 

세 가지 중요한 것은, 나쁜 안전하고 까다로운 일이 될 수 shell=True을 사용하여 알 수 있습니다.
물건을 실행할 때 사용자 입력이나 "알 수없는 변수"를 거의 다루지 않기 때문에 개인적으로 선호합니다. 하지만 몇 마디주의하십시오. 절대로 사용하지 마십시오! 당신이 오류 정기적으로 출력을 분리 할 필요가없는 경우

둘째 존재, 당신은 할 수 있습니다 :

Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

그것은 당신에 대해 걱정 한 적은 파일 핸들을 줄 것이다.

마지막으로, 항상 버퍼를 비우고 항상 버퍼를 닫습니다. 이 두 가지는 중요합니다.
비우지 않으면 응용 프로그램이 가득차 있기 때문에 응용 프로그램이 멈추고 Popen은 더 많은 데이터를 넣을 수 없으므로 비어있는 경우를 기다립니다.
두 번째로 파일 핸들을 닫지 않아서 OS가 가능한 파일 핸들이 부족하여 실행될 수 있습니다. OS가 특정 시점에 열어 놓을 수있는 일괄 처리 파일이 있습니다. 닫히지 않으면 닫을 수 없습니다. 당신의 OS는 조금 쓸모가 없다).

:이 끝날 때까지,

관련 문제