2014-07-08 6 views
1

subprocess.Popen() - 왜 처음과 세 번째는 예상대로 작동하는 동안 두 번째는 여러 파일이나 디렉토리 중 하나를 찾지 못해서 고민? 오류 메시지는 다음과 같습니다파이썬 subprocess.Popen 인수로 쉘 명령에 실패

>ls: Zugriff auf * nicht möglich: Datei oder Verzeichnis nicht gefunden 

영어 번역 : 여기

File not found or directory: access to * not possible 

코드입니다. 기본적 subprocess.Popen()으로 쉘이 명령을 해석하지 않기 때문에

#!/usr/bin/python 
# -*- coding: UTF-8 -*- 

import subprocess 

args = [] 
args.append ('ls') 
args.append ('-al') 

# First does work 
cmd1 = subprocess.Popen(args) 
cmd1.wait() 

# Second does NOT work 
args.append ('*') 
cmd2 = subprocess.Popen(args) 
cmd2.wait() 


# Third does work 
shellcmd = "ls -al *" 
cmd3 = subprocess.Popen(shellcmd, shell=True) 
cmd3.wait() 
+0

번역을위한 thyx – ullix

+0

Popen의 기본값은 shell = False입니다. 따라서 First와 Second는 이런 종류입니다. args에 제공된 인수를 사용합니다. shell = True를 추가하면 args의 첫 번째 인수 만 평가되고 다른 인수는 무시됩니다. 따라서 쉘 명령은 "ls"이며 "ls -al"또는 "ls -al *"가 아닙니다. – ullix

+0

''subprocess.Popen ([ 'ls'])''을 실행하면'subprocess.Popen ([ 'ls', '-al'])'을 실행할 때와 다른 출력을 볼 수 있습니다. 무엇이 작동하지 않는가'subprocess.Popen ([ 'ls', '-al', '*'])''이며 이것은'*'와 관련된 셸 globbing 때문입니다. –

답변

1

이다, 그래서 "*" 파일의 필요한 목록으로 확장되지 않습니다. 전화에 마지막 인수로 shell=True을 추가하십시오.

참고로 the warning in the documentation 사용자 입력이 이러한 방식으로 처리되지 않는다는 것에주의하십시오.

1

이것은 shell globbing 때문에 발생합니다.

기본적으로 * (ls -al *)은 사용 가능한 모든 파일과 일치하도록 사용자 쉘에 의해 확장됩니다. shell=True 플래그없이 하위 프로세스를 실행하면 python이 *을 자체적으로 구문 분석 할 수 없으므로 오류 메시지 ls: cannot access *: No such file or directory이 표시됩니다.

shell=True과 함께 명령을 실행하면 python은 실제로 컨트롤을 셸로 전달하므로 올바른 출력이 표시됩니다.

신뢰할 수없는 소스의 비 초기화 된 입력을 통합하는 셸 명령을 실행하면 프로그램이 셸 주입에 취약 해져 임의의 명령을 실행할 수있는 심각한 보안 결함이 발생하므로 신중하게 사용해야합니다 (see warning here).


EDIT 1

쉘 대체 (globbing)와 Popenargssubprocess module에서 여기

문제를 일으키는 소비 방식 모두,

class subprocess.Popen

args은 프로그램 인수 시퀀스이거나 단일 문자열이어야합니다.

If shell is True , it is recommended to pass args as a 문자열이 아닌 시퀀스.

는 쉘 대체 (globbing)와 Popenargs는 다음의 출력을 비교, 여기에 문제가 소비되는 방식을 이해합니다.2 예 그 참고 만 ls이 실행될 때 shell=True 전달 된 입력은 추천

subprocess.Popen(['ls'])       #works 
subprocess.Popen('ls')       #works 
subprocess.Popen(['ls', '-al'])     #works 
subprocess.Popen(['ls -al'])      #doesn't work raises OSError since not a single command 
subprocess.Popen('ls -al')      #doesn't work raises OSError since not a single command 
subprocess.Popen(['ls -al'], shell=True)   #works since in shell mode 
subprocess.Popen('ls -al', shell=True)   #works since in shell mode & string is single command 
subprocess.Popen(['ls', '-al'], shell=True)  #output corresponds to ls only, list passed instead of string, against recommendation 
subprocess.Popen(['ls', '-al', '*'])    #doesn't work because of shell globbing for * 
subprocess.Popen(['ls -al *'])     #doesn't work raises OSError since not a single commandfor * 
subprocess.Popen('ls -al *')      #doesn't work raises OSError since not a single commandvalid arg 
subprocess.Popen(['ls', '-al', '*'], shell=True) #output corresponds to ls only, list passed instead of string, against recommendation 
subprocess.Popen(['ls -al *'], shell=True)  #works 
subprocess.Popen('ls -al *', shell=True)   #works 
0

하지 귀하의 질문에 직접 대답에 대해하는 list 아닌 string,하지만 당신은 또한을 사용하여 시도 할 수 있기 때문에 파이썬 라이브러리

예 :

from sh import ls 

print ls("-al") 

link to more examples

관련 문제