[python] 서브 프로세스에서 ‘shell = True’의 실제 의미
subprocess
모듈로 다른 프로세스를 호출하고 있습니다. 그러나 질문이 있습니다.
다음 코드에서 :
callProcess = subprocess.Popen(['ls', '-l'], shell=True)
과
callProcess = subprocess.Popen(['ls', '-l']) # without shell
둘 다 작동합니다. 문서를 읽은 후 shell=True
쉘을 통해 코드를 실행 한다는 것을 알게되었습니다 . 즉, 부재시 프로세스가 직접 시작됩니다.
그래서 내 경우에 선호해야 할 것은-프로세스를 실행하고 결과를 얻어야합니다. 쉘 내부 또는 외부에서 호출하면 어떤 이점이 있습니까?
답변
쉘을 통해 전화하지 않는 이점은 ‘미스터리 프로그램’을 호출하지 않는다는 것입니다. POSIX에서 환경 변수 SHELL
는 어떤 바이너리가 “쉘”로 호출되는지를 제어합니다. Windows에는 bourne shell 하위 항목이 없으며 cmd.exe 만 있습니다.
따라서 쉘을 호출하면 사용자가 선택한 프로그램이 호출되며 플랫폼에 따라 다릅니다. 일반적으로 쉘을 통한 호출을 피하십시오.
쉘을 통해 호출하면 쉘의 일반적인 메커니즘에 따라 환경 변수 및 파일 글로브를 확장 할 수 있습니다. POSIX 시스템에서 쉘은 파일 glob을 파일 목록으로 확장합니다. Windows에서는 파일 glob (예 : “*. *”)이 셸에 의해 확장되지 않습니다 (그러나 명령 행의 환경 변수 는 cmd.exe에 의해 확장 됨).
환경 변수 확장 및 파일 글로브를 원한다고 생각 ILS
되면 쉘을 통해 서브 프로그램 호출을 수행 한 네트워크 서비스에 대한 1992 년 의 공격을 조사하십시오 . 여기에는 다양한 sendmail
백도어가 포함 ILS
됩니다.
요약하면을 사용하십시오 shell=False
.
답변
>>> import subprocess
>>> subprocess.call('echo $HOME')
Traceback (most recent call last):
...
OSError: [Errno 2] No such file or directory
>>>
>>> subprocess.call('echo $HOME', shell=True)
/user/khong
0
shell 인수를 true 값으로 설정하면 하위 프로세스가 중간 쉘 프로세스를 생성하고 명령을 실행하도록 지시합니다. 다시 말해서, 중간 쉘을 사용한다는 것은 명령 문자열에서 변수, glob 패턴 및 기타 특수 쉘 기능이 명령이 실행되기 전에 처리됨을 의미합니다. 이 예에서 $ HOME은 echo 명령 전에 처리되었습니다. 실제로 이것은 쉘 확장을 사용하는 명령의 경우이며 ls -l 명령은 간단한 명령으로 간주됩니다.
소스 : 서브 프로세스 모듈
답변
Shell = True에서 문제가 발생할 수있는 예는 다음과 같습니다.
>>> from subprocess import call
>>> filename = input("What file would you like to display?\n")
What file would you like to display?
non_existent; rm -rf / # THIS WILL DELETE EVERYTHING IN ROOT PARTITION!!!
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...
여기에서 문서를 확인하십시오 : subprocess.call ()
답변
쉘을 통해 프로그램을 실행한다는 것은 프로그램에 전달 된 모든 사용자 입력이 호출 된 쉘의 구문과 의미 규칙에 따라 해석됨을 의미합니다. 기껏해야 사용자가 이러한 규칙을 준수해야하기 때문에 사용자에게 불편을 초래할뿐입니다. 예를 들어, 따옴표 나 공백과 같은 특수 쉘 문자가 포함 된 경로는 이스케이프해야합니다. 최악의 경우 사용자가 임의의 프로그램을 실행할 수 있기 때문에 보안 누출이 발생합니다.
shell=True
단어 분할 또는 매개 변수 확장과 같은 특정 쉘 기능을 사용하는 것이 편리한 경우가 있습니다. 그러나 이러한 기능이 필요한 경우 다른 모듈을 사용하십시오 (예 : os.path.expandvars()
매개 변수 확장 또는 shlex
워드 분할). 이것은 더 많은 작업을 의미하지만 다른 문제는 피합니다.
한마디로 : 피하십시오 shell=True
.
답변
여기에있는 다른 답변은 subprocess
문서에 언급 된 보안주의 사항을 적절히 설명합니다 . 그러나 그 외에도 쉘을 시작하여 실행하려는 프로그램을 시작하는 오버 헤드는 종종 쉘 기능을 실제로 사용하지 않는 상황에서는 불필요하고 어리 석습니다. 또한, 특히 숨겨진 쉘이나 제공하는 서비스에 익숙하지 않은 경우 숨겨진 추가 복잡성이 두렵 습니다.
쉘과의 상호 작용이 사소한 것이 아니라면, 이제 파이썬 스크립트와 쉘 스크립트를 모두 이해하기 위해 파이썬 스크립트의 독자와 관리자 (나중에있을 수도 있고 아닐 수도 있음)가 필요합니다. “명시적인 것이 묵시적인 것보다 낫다” 라는 파이썬 모토를 기억하십시오 . 파이썬 코드가 동등한 (그리고 종종 매우 간결한) 쉘 스크립트보다 다소 복잡 할지라도 쉘을 제거하고 기능을 원시 파이썬 구문으로 대체하는 것이 좋습니다. 외부 프로세스에서 수행되는 작업을 최소화하고 가능한 한 자신의 코드 내에서 제어를 유지하는 것은 가시성을 향상시키고 원하거나 원치 않는 부작용의 위험을 줄임으로써 종종 좋은 생각입니다.
와일드 카드 확장, 변수 보간 및 리디렉션은 모두 기본 Python 구문으로 간단하게 대체 할 수 있습니다. 파이썬에서 일부 또는 전부를 합리적으로 다시 작성할 수없는 복잡한 쉘 파이프 라인은 아마도 쉘 사용을 고려할 수있는 상황입니다. 여전히 성능 및 보안 관련 사항을 이해해야합니다.
사소한 경우에는 피하기 위해 shell=True
간단히 교체하십시오.
subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)
와
subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])
첫 번째 인수가 전달할 문자열 목록이며 문자열 execvp()
및 백 슬래시 이스케이프 쉘 메타 문자를 인용하는 것이 일반적으로 필요하지 않은 (유용하거나 올바른) 방법에 주목 하십시오. 어쩌면 쉘 변수를 따옴표로 묶을 때를 참조하십시오 .
따로, 패키지 Popen
의 가장 간단한 래퍼 중 하나가 원하는 것을 수행하는 경우가 종종 subprocess
있습니다. 최근에 충분한 파이썬을 가지고 있다면 아마도을 사용해야 subprocess.run
합니다.
- 함께
check=True
명령이 실패 실행 한 경우 그것이 실패합니다. - 로
stdout=subprocess.PIPE
그 명령의 출력을 캡처합니다. - 다소 모호하게도
universal_newlines=True
출력을 적절한 유니 코드 문자열로 디코딩합니다 (bytes
Python 3의 경우 시스템 인코딩에 있습니다).
그렇지 않은 경우, 많은 태스크의 경우, check_output
명령이 성공했는지 확인하거나 check_call
수집 할 출력이 없는지 명령에서 출력을 얻으려고합니다 .
David Korn의 인용을 인용하겠습니다. “휴대용 쉘 스크립트보다 이식 가능한 쉘을 작성하는 것이 더 쉽습니다.” 심지어 subprocess.run('echo "$HOME"', shell=True)
Windows로 이식 할 수 없습니다.