쉘 명령을 직접 실행하는 대신 Python의 os 모듈 메소드를 사용하는 이유는 무엇입니까?


157

나는 그런 파일 / 디렉토리를 생성하는 파일 속성을 변경하는 등 대신에 단지를 통해 해당 명령을 실행으로 OS 특정 작업을 실행하기위한 파이썬 라이브러리 함수를 사용하여 뒤에있는 동기 부여 무엇을 이해하려고 os.system()하거나 subprocess.call()?

예를 들어 왜하지 os.chmod않고 사용 하고 os.system("chmod...")싶습니까?

쉘 명령을 직접 실행하는 대신 가능한 파이썬의 라이브러리 메소드를 최대한 많이 사용하는 것이 "파이썬"이라는 것을 이해합니다. 그러나 기능적 관점에서이 작업을 수행하는 데 다른 동기가 있습니까?

여기서는 간단한 한 줄 쉘 명령 실행에 대해서만 이야기하고 있습니다. 우리는 작업 실행에 대한 더 많은 제어가 필요할 때 subprocess예를 들어 모듈 을 사용 하는 것이 더 의미가 있음을 이해합니다 .


6
당신은 기본적으로 머리에 못을 쳤습니다. 언급 한 OS 수준의 작업은 os.system을 통해 호출되는 대신 자신의 기능을 보증 할만큼 충분히 일반적입니다.
deweyredman

7
BTW, 당신은 실행 시간을 정하려고 했습니까 -os.chmodos.system ( "chmod ...") . 나는 그것이 당신의 질문의 일부에 대답 할 것이라고 추측 할 위험이 있습니다.
화산

61
왜이 print때 수 os.system("echo Hello world!")?
user253751 2019

25
같은 이유로 os.path경로를 수동으로 처리하는 대신 처리해야합니다. 경로는 실행되는 모든 OS에서 작동합니다.
Bakuriu

51
"쉘 명령을 직접 실행"은 실제로 직접적입니다. 쉘은 시스템에 대한 저수준 인터페이스 os.chmod가 아니며 chmod쉘이 할 프로그램 을 호출하지 않습니다 . 을 사용 os.system('chmod ...')하면 셸을 시작하여 문자열을 해석하여 다른 실행 파일을 호출하여 C chmod함수를 호출하고 C을 os.chmod(...)훨씬 더 직접 호출합니다 chmod.
user2357112는 Monica

답변:


325
  1. 그건 더 빨리 , os.system그리고 subprocess.call일이 간단한에 대한 필요는 새로운 프로세스를 생성합니다. 사실, os.system그리고 subprocess.callshell쉘되는 첫 번째, 그리고 (가 내장 같은 쉘이 아니라면 실행중인 것을 명령 인 두 번째 : 인수 일반적으로 두 개 이상의 새로운 프로세스를 생성 test).

  2. 일부 명령은 별도의 프로세스에서 쓸모없습니다 . 예를 들어을 실행 os.spawn("cd dir/")하면 자식 프로세스의 현재 작업 디렉토리가 변경되지만 Python 프로세스는 변경되지 않습니다. 당신은 그것을 사용해야 os.chdir합니다.

  3. 쉘이 해석 하는 특수 문자 에 대해 걱정할 필요가 없습니다 . os.chmod(path, mode)파일 이름이 무엇이든간에 작동하지만 os.spawn("chmod 777 " + path)파일 이름이과 같은 경우 끔찍하게 실패 ; rm -rf ~합니다. 인수 subprocess.call없이 사용하면이 문제를 해결할 수 있습니다 shell.

  4. 대시로 시작하는 파일 이름 에 대해 걱정할 필요가 없습니다 . os.chmod("--quiet", mode)는 파일 이름의 권한을 변경 --quiet하지만 인수로 해석되므로 os.spawn("chmod 777 --quiet")실패 --quiet합니다. 이것도 마찬가지입니다 subprocess.call(["chmod", "777", "--quiet"]).

  5. 파이썬의 표준 라이브러리가 당신을 위해 처리해야하기 때문에 크로스 플랫폼 과 크로스 셸 문제 가 적습니다 . 시스템에 chmod명령이 있습니까? 설치되어 있습니까? 지원할 것으로 예상되는 매개 변수를 지원합니까? os이 불가능하다고 할 때 모듈은 가능한 크로스 플랫폼 및 문서로 일하려고합니다.

  6. 실행중인 명령에 관심있는 출력 이있는 경우, 코너 케이스 (공백, 탭 및 줄 바꿈이있는 파일 이름)를 잊어 버릴 수 있으므로 소리보다 까다로워 야합니다. 이식성에 신경 쓰지 마십시오.


38
"크로스 플랫폼"지점에 추가하기 위해 디렉토리를 나열하는 것은 Linux에서 "ls", Windows에서 "dir"입니다. 디렉토리의 내용을 얻는 것은 매우 일반적인 저수준 작업입니다.
Cort Ammon

1
@CortAmmon : "낮은 수준"상대적, ls또는 dir단지로, 개발자의 특정 유형의 꽤 높은 수준이다 bash하거나 cmd또는 ksh당신이 선호하는 또는 어떤 쉘.
Sebastian Mach

1
@ phresnel : 그런 식으로 생각하지 않았습니다. 나에게 "OS의 커널 API에 대한 직접 호출"은 매우 낮은 수준이었습니다. 나는 자연스럽게 내 편견으로 접근하기 때문에 나를 피하는 다른 관점이 있다고 가정합니다.
Cort Ammon

5
@CortAmmon : 맞습니다 ls. OS 커널 API를 직접 호출하지 않기 때문에 그보다 더 높은 수준입니다. (작은) 응용 프로그램입니다.
Steve Jessop

1
@SteveJessop. 나는 "디렉토리의 내용을 얻는 중"이라고 저수준이라고했습니다. 나는 생각하고 있지 않다 ls또는 diropendir()/readdir()(리눅스 API) 또는 FindFirstFile()/FindNextFile()(윈도우 API) 또는 File.listFiles(자바 API) 또는 Directory.GetFiles()(C #)를. 이 모든 것은 OS에 대한 직접 호출과 밀접한 관련이 있습니다. 일부는 레지스터에 숫자를 넣고 int 13h커널 모드를 트리거하기 위해 호출하는 것처럼 간단 할 수 있습니다 .
Cort Ammon

133

더 안전합니다. 여기에 아이디어를 제공하는 예제 스크립트가 있습니다.

import os
file = raw_input("Please enter a file: ")
os.system("chmod 777 " + file)

사용자의 입력 인 경우 test; rm -rf ~홈 디렉토리가 삭제됩니다.

이것이 내장 기능을 사용하는 것이 더 안전한 이유입니다.

따라서 시스템 대신 하위 프로세스를 사용해야하는 이유는 무엇입니까?


26
또는 그것을 보는 또 다른 방법, 올바른 프로그램, 파이썬 프로그램 또는 쉘 스크립트를 작성하는 파이썬 프로그램을 작성하는 것이 더 쉬운 방법은 무엇입니까? :-)
Steve Jessop 2019

3
@SteveJessop, 내 동료는 작은 Python 스크립트를 작성하여 20 배 더 빨리 탄 쉘 스크립트를 작성하는 데 놀랐습니다. 출력 리디렉션이 섹시하게 보일 수 있다고 설명했지만 각 반복에서 파일을 열고 닫는 것이 필요합니다. 그러나 일부 사랑은 물건 어려운 방법을 수행하는 - :
화산

1
@SteveJessop, 이것은 까다로운 질문입니다. 런타임까지는 알 수 없습니다! :)

60

명령을 실행할 때 또는 os모듈을 사용 하는 것보다 모듈 에서 Python의보다 구체적인 메소드를 선호하는 경우가 4 가지 있습니다 .os.systemsubprocess

  • 중복성 -다른 프로세스를 생성하는 것은 중복되며 시간과 자원을 낭비합니다.
  • 이식성 - os모듈 의 많은 메소드는 여러 플랫폼에서 사용 가능하지만 많은 쉘 명령은 운영 체제마다 다릅니다.
  • 결과 이해 -임의의 명령을 실행하기 위해 프로세스를 생성하면 출력 결과를 구문 분석하고 명령이 잘못한 이유이유를 이해해야 합니다 .
  • 안전 -프로세스는 주어진 명령을 실행할 수 있습니다. 이것은 약한 디자인이며 os모듈 에서 특정 방법을 사용하면 피할 수 있습니다 .

이중화 ( 중복 코드 참조 ) :

실제로 최종 시스템 호출 ( chmod예 :)로가는 도중에 중복 "중간자"를 실행하고 있습니다. 이 중개인은 새로운 프로세스 또는 하위 셸입니다.

보낸 사람 os.system:

서브 쉘에서 명령 (문자열)을 실행합니다 ...

그리고 subprocess산란 새로운 프로세스에 불과 모듈입니다.

이러한 프로세스를 생성하지 않고도 필요한 것을 수행 할 수 있습니다.

이식성 ( 소스 코드 이식성 참조 ) :

os모듈의 목표는 일반적인 운영 체제 서비스를 제공하는 것이며 그 설명은 다음으로 시작합니다.

이 모듈은 운영 체제 종속 기능을 사용하는 이식 가능한 방법을 제공합니다.

os.listdir윈도우와 유닉스 모두에서 사용할 수 있습니다 . 이 기능에 os.system/ 를 사용하려고하면 subprocess두 개의 통화 ( ls/ dir) 를 유지 관리 하고 사용중인 운영 체제를 확인해야합니다. 이것은 이식성이 없으며 나중에 더 많은 좌절 일으킬 입니다 ( 출력 처리 참조 ).

명령 결과 이해 :

디렉토리에 파일을 나열하려고한다고 가정하십시오.

os.system("ls")/를 사용하는 경우 subprocess.call(['ls'])프로세스의 출력 만 다시 가져올 수 있습니다. 기본적으로 파일 이름이있는 큰 문자열입니다.

파일 이름에 공백이있는 파일을 두 파일에서 어떻게 알 수 있습니까?

파일을 나열 할 권한이 없으면 어떻게합니까?

데이터를 파이썬 객체에 어떻게 매핑해야합니까?

이것들은 내 머리 꼭대기에 있으며이 문제에 대한 해결책이 있지만 왜 당신을 위해 해결 된 문제를 다시 해결합니까?

이것은 이미 존재하며 자유롭게 사용할 수있는 구현을 반복 하지 않음 으로써 자신을 반복하지 않음 원칙 (종종 "건조"라고 함) 을 따르는 예입니다 .

안전:

os.system하고 subprocess강력하다. 이 힘이 필요할 때는 좋지만, 그렇지 않을 때는 위험합니다. 당신이 사용하는 경우 os.listdir, 당신은 알고 그것을 어떤 다른 다른 다음 목록 파일을하거나 오류를 발생시킬 수 없습니다. 동일한 동작 을 사용 os.system하거나 subprocess달성 할 때 의도하지 않은 작업을 수행 할 수 있습니다.

주입 안전 ( 쉘 주입 예 참조 ) :

사용자의 입력을 새 명령으로 사용하는 경우 기본적으로 쉘을 제공합니다. 이것은 사용자를 위해 DB에 쉘을 제공하는 SQL 주입과 매우 유사합니다.

예를 들면 다음과 같은 형식의 명령이 있습니다.

# ... read some user input
os.system(user_input + " some continutation")

이것은 쉽게 실행하는 데 악용 될 수 있는 다음 입력을 사용하여 임의의 코드를 NASTY COMMAND;#최종를 만들 :

os.system("NASTY COMMAND; # some continuation")

시스템을 위험에 빠뜨릴 수있는 명령이 많이 있습니다.


3
나는 2가 주된 이유라고 말할 것입니다.
jaredad7 7

23

간단한 이유로-쉘 함수를 호출하면 명령이 존재하면 파괴되는 하위 쉘이 생성되므로 쉘에서 디렉토리를 변경하면 파이썬의 환경에 영향을 미치지 않습니다.

또한 하위 셸을 만드는 데 시간이 오래 걸리므로 OS 명령을 직접 사용하면 성능에 영향을줍니다

편집하다

몇 가지 타이밍 테스트를 실행했습니다.

In [379]: %timeit os.chmod('Documents/recipes.txt', 0755)
10000 loops, best of 3: 215 us per loop

In [380]: %timeit os.system('chmod 0755 Documents/recipes.txt')
100 loops, best of 3: 2.47 ms per loop

In [382]: %timeit call(['chmod', '0755', 'Documents/recipes.txt'])
100 loops, best of 3: 2.93 ms per loop

내부 기능이 10 배 이상 빠르게 실행

편집 2

외부 실행 파일을 호출하면 Python 패키지보다 더 나은 결과를 얻을 수있는 경우가 있습니다. 하위 프로세스를 통해 호출 된 gzip 의 성능이 자신이 사용한 Python 패키지의 성능보다 훨씬 높다는 내 동료가 보낸 메일을 기억했습니다 . 그러나 표준 OS 명령을 에뮬레이트하는 표준 OS 패키지에 대해 이야기 할 때는 확실히 아닙니다


우연히 iPython으로 완료 되었습니까? %일반 인터프리터 를 사용하여 시작하는 특수 함수를 사용할 수 있다고 생각하지 않았습니다 .
iProgram

@ aPyDeveloper, 그렇습니다. 우분투에서 iPython이었습니다. "마 법적" % timeit 은 축복입니다. 일부 경우가 있습니다 – 대부분 문자열 형식 – 처리 할 수 ​​없음
화산

1
또는 파이썬 스크립트를 만든 다음 time <path to script> 터미널에 입력 하면 실제, 사용자 및 프로세스 시간을 알 수 있습니다. iPython이없고 Unix 명령 행에 액세스 할 수있는 경우입니다.
iProgram

1
@aPyDeveloper, 열심히 일해야 할 이유가 없습니다-iPython을 컴퓨터에 가지고있을 때
화산

진실! iPython이 없다면 말 했어요. :)
iProgram

16

쉘 호출은 OS마다 다르지만 대부분의 경우 Python os 모듈 기능은 그렇지 않습니다. 그리고 하위 프로세스를 생성하지 않습니다.


1
파이썬 모듈 함수는 또한 새로운 서브 쉘을 호출하기 위해 새로운 서브 프로세스를 생성합니다.
Koderok

7
@Koderok 말도 안되는, 모듈 함수는 인-프로세스
dwurf

3
@ Koderok : os 모듈은 쉘 명령이 사용하는 기본 시스템 호출을 사용하며 쉘 명령을 사용하지 않습니다. 이것은 os 시스템 호출이 일반적으로 쉘 명령보다 안전하고 빠릅니다 (문자열 구문 분석, 부 포크, exec 없음, 대신 커널 호출 임). 대부분의 경우, 쉘 호출과 시스템 호출은 종종 유사하거나 동일한 이름을 갖지만 별도로 문서화되어 있습니다. 쉘 호출은 man 섹션 1 (기본 man 섹션)에 있고 동등한 이름의 시스템 호출은 man 섹션 2에 있습니다 (예 : man 2 chmod).
거짓말 라이언

1
@ dwurf, LieRyan : 내 나쁜! 나는 잘못된 생각을 가지고있는 것 같습니다. 감사!
Koderok

11

훨씬 더 효율적입니다. "쉘"은 많은 시스템 호출을 포함하는 또 다른 OS 바이너리입니다. 단일 시스템 호출에 대해서만 전체 쉘 프로세스를 작성하는 오버 헤드가 발생하는 이유는 무엇입니까?

os.system쉘 내장이 아닌 무언가를 사용할 때 상황은 더욱 악화됩니다 . 쉘 프로세스를 시작하여 실행 파일을 시작한 다음 (두 프로세스가 떨어져) 시스템을 호출합니다. 최소한 subprocess쉘 중개 프로세스의 필요성을 제거했을 것입니다.

이것은 파이썬에만 국한된 것이 아닙니다. systemd같은 이유로 Linux 시작 시간이 이렇게 개선되었습니다. 이는 수천 개의 쉘을 생성하는 대신 필요한 시스템 호출 자체를 만듭니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.