[python] 파이썬에서 외부 명령 호출

파이썬 스크립트에서 외부 명령 (유닉스 쉘이나 Windows 명령 프롬프트에서 입력 한 것처럼)을 어떻게 호출합니까?



답변

표준 라이브러리에서 서브 프로세스 모듈을 보십시오 .

import subprocess
subprocess.run(["ls", "-l"])

의 장점 subprocess대는 system가 (당신이 얻을 수있는 더 유연하다는 것이다 stdout, stderr, “진짜”상태 코드, 더 나은 오류 처리, 등 …).

공식 문서는 권장 subprocess대체를 통해 모듈 os.system():

subprocess모듈은 새로운 프로세스를 생성하고 결과를 검색 할 수있는보다 강력한 기능을 제공합니다. 이 기능을 사용하는 것보다 해당 모듈을 사용하는 것이 좋습니다 os.system().

문서의 이전 프로세스를 서브 프로세스 모듈로 대체 섹션에 subprocess유용한 레시피가있을 수 있습니다.

3.5 이전의 Python 버전의 경우 call다음을 사용하십시오 .

import subprocess
subprocess.call(["ls", "-l"])


답변

다음은 외부 프로그램을 호출하는 방법과 각각의 장단점을 요약 한 것입니다.

  1. os.system("some_command with args")명령과 인수를 시스템 쉘에 전달합니다. 실제로이 방법으로 여러 명령을 한 번에 실행하고 파이프 및 입 / 출력 리디렉션을 설정할 수 있기 때문에 좋습니다. 예를 들면 다음과 같습니다.

    os.system("some_command < input_file | another_command > output_file")  

그러나 이것은 편리하지만 공백과 같은 쉘 문자의 이스케이프 처리를 수동으로 처리해야합니다. 반면에, 이것은 실제로 외부 프로그램이 아닌 단순히 쉘 명령 인 명령을 실행할 수있게합니다. 설명서를 참조하십시오 .

  1. stream = os.popen("some_command with args")os.system해당 프로세스의 표준 입 / 출력에 액세스하는 데 사용할 수있는 파일과 유사한 객체를 제공한다는 점을 제외하고 는 동일한 작업을 수행합니다 . 모두 다른 방식으로 i / o를 처리하는 3 가지 다른 종류의 popen이 있습니다. 모든 것을 문자열로 전달하면 명령이 셸로 전달됩니다. 당신이 그들을 목록으로 전달하면 아무것도 탈출에 대해 걱정할 필요가 없습니다. 설명서를 참조하십시오 .

  2. 모듈 의 Popen클래스 subprocess. 이것은 대체 용으로 고안 os.popen되었지만 너무 포괄적이기 때문에 약간 더 복잡하다는 단점이 있습니다. 예를 들어 다음과 같이 말할 수 있습니다.

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()

    대신에:

    print os.popen("echo Hello World").read()

    그러나 4 가지 다른 popen 함수 대신 하나의 통합 클래스에서 모든 옵션을 사용하는 것이 좋습니다. 설명서를 참조하십시오 .

  3. 모듈 의 call기능 subprocess. 이것은 기본적으로 Popen클래스와 같으며 동일한 인수를 모두 사용하지만 명령이 완료 될 때까지 기다렸다가 리턴 코드를 제공합니다. 예를 들면 다음과 같습니다.

    return_code = subprocess.call("echo Hello World", shell=True)  

    설명서를 참조하십시오 .

  4. Python 3.5 이상을 사용하는 subprocess.run경우 위와 비슷하지만 더 유연하고 CompletedProcess명령 실행이 완료되면 객체를 반환하는 새로운 함수를 사용할 수 있습니다 .

  5. os 모듈에는 C 프로그램에서 가질 수있는 모든 fork / exec / spawn 함수가 있지만 직접 사용하지 않는 것이 좋습니다.

subprocess아마도 당신이 사용 하는 모듈 일 것입니다.

마지막으로 쉘이 문자열로 실행하도록 최종 명령을 전달하는 모든 메소드에 대해 이스케이프 처리해야합니다. 전달하는 문자열의 일부를 완전히 신뢰할 수없는 경우 보안에 심각한 영향을 미칩니다 . 예를 들어, 사용자가 문자열의 일부 또는 일부를 입력하는 경우. 확실하지 않은 경우 상수와 함께이 방법 만 사용하십시오. 의미에 대한 힌트를 제공하려면 다음 코드를 고려하십시오.

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

사용자가 전체 파일 시스템을 지울 수있는 “엄마가 나를 사랑하지 않는 && rm -rf /”라는 것을 입력했다고 상상해보십시오.


답변

일반적인 구현 :

import subprocess

p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,
retval = p.wait()

stdout파이프 의 데이터로 원하는 것을 자유롭게 할 수 있습니다 . 실제로 이러한 매개 변수 ( stdout=stderr=) 를 생략하면 다음 과 같이 작동합니다 os.system().


답변

하위 프로세스를 호출 프로세스에서 분리하는 방법에 대한 힌트 (백그라운드에서 하위 프로세스 시작).

CGI 스크립트에서 긴 작업을 시작한다고 가정합니다. 즉, 하위 프로세스는 CGI 스크립트 실행 프로세스보다 오래 지속되어야합니다.

서브 프로세스 모듈 문서의 전형적인 예는 다음과 같습니다.

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

longtask.py가 끝날 때까지 ‘call subprocess’줄을 기다리지 않기를 원합니다. 그러나 예제에서 ‘여기에 더 많은 코드가 있습니다’행 이후에 어떤 일이 발생하는지 명확하지 않습니다.

내 목표 플랫폼은 FreeBSD 였지만 개발은 Windows에 있었으므로 Windows에서 먼저 문제에 직면했습니다.

Windows (Windows XP)에서는 longtask.py가 작업을 완료 할 때까지 상위 프로세스가 완료되지 않습니다. CGI 스크립트에서 원하는 것이 아닙니다. 이 문제는 파이썬에만 국한된 것이 아닙니다. PHP 커뮤니티에서 문제는 동일합니다.

해결책은 DETACHED_PROCESS Process Creation Flag 를 Windows API의 기본 CreateProcess 함수에 전달하는 것입니다. pywin32를 설치 한 경우 win32process 모듈에서 플래그를 가져올 수 있습니다. 그렇지 않으면 직접 정의해야합니다.

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/ * UPD 2015.10.27 @eryksun 아래 주석에서 의미 적으로 올바른 플래그는 CREATE_NEW_CONSOLE (0x00000010) * /입니다.

FreeBSD에는 또 다른 문제가 있습니다. 부모 프로세스가 완료되면 자식 프로세스도 완료됩니다. 그리고 그것은 CGI 스크립트에서 원하는 것이 아닙니다. 일부 실험에서는 sys.stdout을 공유하는 데 문제가있는 것으로 나타났습니다. 작업 솔루션은 다음과 같습니다.

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

다른 플랫폼에서 코드를 확인하지 않았으며 FreeBSD에서 동작의 이유를 모릅니다. 누구나 알고 있다면 아이디어를 공유하십시오. 파이썬에서 백그라운드 프로세스를 시작하는 인터넷 검색은 아직 밝혀지지 않았습니다.


답변

import os
os.system("your command")

명령이 정리되지 않았으므로 위험합니다. ‘os’및 ‘sys’모듈에 대한 관련 문서는 Google에 맡기십시오. 비슷한 기능을 수행하는 많은 함수 (exec * 및 spawn *)가 있습니다.


답변

os.system 대신 subprocess 모듈을 사용하는 것이 좋습니다. 쉘 이스케이프 처리가 훨씬 안전하기 때문입니다.

subprocess.call(['ping', 'localhost'])


답변

import os
cmd = 'ls -al'
os.system(cmd)

명령 결과를 반환하려면을 사용할 수 있습니다 os.popen. 그러나 이것은 하위 프로세스 모듈 을 선호하여 버전 2.6 이후 더 이상 사용되지 않으며 다른 답변도 잘 다루었습니다.