2014-04-13 2 views
1

코딩이 새로 워, 도움이 필요합니다. 나는 디렉터리의 내용을 통과하는 python 스크립트를 작성 중이며 디렉토리를 통해 각 파일을 Bluetooth 장치로 보낼 것입니다.파이썬 - 서브 프로세스에서 변수 사용하기. 팝업 명령

파일 이름을 지정하면 올바르게 작동하지만 파일 이름을 변수로 사용하여 작동시키지 못합니다. 여기에 내가 다음과 같은 변수 '파일'로 명령 '에서는 image1.jpg'을 대체하기 위해 노력하고 있지만 성공하지

import os 
import time 
import subprocess 

indir = '\\\\10.12.12.218\\myshare' 
for root, dirs, filenames in os.walk(indir): 
    for file in filenames: 
     print (file) 
     subprocess.Popen('ussp-push /dev/rfcomm0 image1.jpg file.jpg', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
print ('end') 

아래의 코드입니다.

subprocess.Popen('ussp-push /dev/rfcomm0', file, 'file.jpg', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

정말 도움이된다.

+0

문서의 [Popen() 함수의 서명] (https://docs.python.org/3/library/subprocess.html#subprocess.Popen)을 보았습니까? – jfs

답변

0

이 시도 :

subprocess.Popen(
    ['ussp-push', '/dev/rfcomm0', file, 'file.jpg'], 
    stdout=subprocess.PIPE, 
    stderr=subprocess.PIPE) 

당신은 Popen()에 문자열 목록을 전달하려는. 다른 방법으로는 다음과 같은 공간 구분 명령을 작성하는 것입니다.

subprocess.Popen(
    'ussp-push /dev/rfcomm0 "{0}" file.jpg'.format(file) # replace {0} with file 
    stdout=subprocess.PIPE, 
    stderr=subprocess.PIPE) 

shell = True Unsafe입니까?

shell=True과 관련하여 몇 가지 요령을 작성하고자합니다. 주석 아웃 m.wasowski 지점으로이 경우

  1. , 그것은 필요가 없습니다.
  2. shell=True 명령에 대한 제어 권한이 없으면 안전하지 않습니다. 예를 들어, 사용자 입력에서 명령을받는 경우 사용자는 sudo rm -fr /과 같은 것을 전달할 수 있습니다.
  3. 일단 쉘을 호출하면 PATH이 다를 수 있으므로 안전하지 않습니다. 당신이 ls과 같은 명령을 발행 할 때, 그것은 같은 /home/evil/bin 말했다되고 그건

명령을 제어 할 경우, shell=True이에, 안전 일반적인 장소 (/bin/ls)하지만 일부 악의적 인 곳에서 제공하지 않을 수 있습니다 case, /dev/rfcomm0 - 다른 곳에서 명령을받는 대신 명령을 정의하십시오. 이 점 양육을 위해 m.wasowski 고맙습니다.

업데이트

shell=True를 제거합니다. 의견보기.

+0

명령 줄 인수 목록을 전달할 때, 특히 안전하지 않기 때문에'shell = True'가 필요하지 않습니다 ... –

+0

-1 올바르지 않습니다. 리스트 인수와'shell = True'를 함께 사용하지 마십시오. 거의 항상 오류입니다 : 모든 목록 항목은 셸로 전달됩니다.,'/ dev/rfcomm0'는'ussp-push' 대신 POSIX 환경을 가정하고'/ bin/sh'에 인자로 전달됩니다. – jfs

+0

여전히 올바르지 않습니다. ''ussp-push/dev/rfcomm0 file.jpg '와 같은 ** 문자열 ** 인자는 POSIX에서'shell = True'를 요구합니다. 내가 말했다 : _ "** list ** 인수와'shell = True'를 함께 사용하지 마십시오."_ – jfs

2

은 몇 가지 문제가 있습니다

  • shell=True이 필요하지 않습니다. 목록 인수를 삭제하고 사용이 Popen에 대해 별도의 인수로 명령 줄 인수를 전달하려고하는

    import shlex 
    
    args = shlex.split('ussp-push /dev/rfcomm0 image1.jpg file.jpg') 
    
  • . Popen('echo', 'a') 대신 Popen(['echo', 'a'])을 사용하십시오. 나중에 완전히 잘못되었습니다.참조 Popen() function signature in the docs

  • 당신이 그렇지 않으면 자식 프로세스는 OS 파이프 버퍼 중 하나를 채우는 경우 영원히 차단 될 수 p.stdout/p.stderr 파이프에서 읽을하지 않는

  • Popen()에 대한 참조를 저장 stdout=PIPE 및/또는 stderr=PIPE를 사용하지 않는 나중에 상태를 기다린다. 그것은 선택 사항이지만 너무 많은 좀비

당신은 별도의 함수로 일부를 생성하는 파일을 추출 할 수 생성 방지하는 데 도움이 : 그럼

import os 

def get_files(indir, extensions=('.jpg', '.png')): 
    """Yield all files in `indir` with given `extensions` (case-insensitive).""" 
    for root, dirs, files in os.walk(indir): 
     for filename in files: 
      if filename.casefold().endswith(extensions): 
       yield os.path.join(root, filename) 

병렬로 각 파일에 대해 명령을 실행 :

from subprocess import CalledProcessError, Popen 

indir = r'\\10.12.12.218\myshare' 
commands = [['ussp-push', '/dev/rfcomm0', path] for path in get_files(indir)] 

# start all child processes 
children = [Popen(cmd) for cmd in commands] 

# wait for them to complete, raise an exception if any of subprocesses fail 
for process, cmd in zip(children, commands): 
    if process.wait() != 0: 
     raise CalledProcessError(process.returncode, cmd)   

당신은 그럼 그냥 subprocess.Popen 대신 subprocess.call을 사용하여 병렬로 명령을 실행하지 않으려면 :

import subprocess 

indir = r'\\10.12.12.218\myshare' 
statuses = [subprocess.call(['ussp-push', '/dev/rfcomm0', path]) 
      for path in get_files(indir)] 
if any(statuses): 
    print('some commands have failed') 

한 번에 하나의 명령을 실행합니다.

+0

정보를 제공해 주셔서 감사합니다. 여기에 언급 한 내용 중 많은 부분이 제 지식보다 뛰어납니다. 나는 그럭저럭 명령을 vairable에 저장하고 코드를 변경함으로써 코드를 변경하는 일을 할 수 있었지만, 루프의 주먹 반복만으로 howerver를 작동시켰다. 두 번째로 실행하면 파일을 블루투스 장치로 보낸다. 어떤 아이디어가 잘못 될 수 있습니까? – user3529962

+0

다음은 'indir = \\\\ 10.12.12.218 \\ testshare os.walk (indir)의 루트, dirs, 파일 이름을 변경 한 코드입니다. 파일명이 f인 경우 : command = "ussp-push/dev ('command', shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE) print ('end') – user3529962

+0

@ rfcc0 "+ f +"file.jpg " print (f) subprocess.Popen user3529962 : 내 대답의 코드를 사용하십시오. 당신이 어떤 라인을 사용하는지 이해하지 못한다면; 청하다. – jfs

0

그래서 여러 파일이 있으며 각 파일을 인수로 한 번 명령을 실행하려고합니다. 다음은 잘 작동해야한다고 생각합니다.

import os 
import time 
import subprocess 

indir = '\\\\10.12.12.218\\myshare' 
for root, dirs, filenames in os.walk(indir): 
    for file in filenames: 
     print 'Sending', os.path.join(root, file) 
     subprocess.check_call(['ussp-push', '/dev/rfcomm0', os.path.join(root, file), 'file.jpg']) 
print ('end') 

여기에 내가 만든 변경 사항 : 당신이 병렬로 순차적이 아닌 명령을 실행 원하는대로 내가 대신 Popencheck_call 기능을 사용하고

  1. . check_call 함수는 Popen과 같은 인수를 사용하지만 프로세스가 완료 될 때까지 대기하고 프로세스가 실패 할 경우 예외를 발생시킵니다.
  2. 첫 번째 인수로 배열 (대괄호로 작성)을 전달할 때, 명령은 check_call으로 전달됩니다. 이것은 또한 이 명령 문자열을 해석 할 필요가 없음을 의미하므로 shell=True을 제거했습니다. 이 배열의 첫 번째 항목은 나머지 명령이 전달되는 명령입니다.
  3. 배열의 마지막 항목은 파일의 전체 경로입니다. file 변수는 파일의 이름 만 보유합니다. 그러나 우리는 그 경로가 폴더 안의 어딘가에있을 수 있기 때문에 경로가 필요합니다 (재귀 적으로는 walk입니다). os.path.join은 해당 플랫폼에서 \ 또는 /으로 두 개의 문자열을 조인합니다.
  4. 나는 또한 stdoutstderr 인수를 제거했습니다. 이것은 명령의 출력과 오류가 명령 줄에서 나타나기를 원한다는 것을 의미합니다. stdoutstderr 인수는 명령의 출력을 읽고 터미널에서 표시하지 않고 직접 처리하려는 경우에 유용합니다.
관련 문제