파이썬에서 서브프로세스란? [5 사용 예]

게시 됨: 2021-05-23

하위 프로세스를 사용하면 운영 체제와 완전히 새로운 수준에서 상호 작용할 수 있습니다.

우리 컴퓨터는 항상 하위 프로세스를 실행합니다. 사실, 이 기사를 읽는 것만으로도 네트워크 관리자나 인터넷 브라우저 자체와 같은 많은 프로세스를 실행하고 있는 것입니다.

이것에 대한 멋진 점은 컴퓨터에서 수행하는 모든 작업에 하위 프로세스 호출이 포함된다는 것입니다. 이는 파이썬으로 간단한 "hello world" 스크립트를 작성하는 경우에도 마찬가지입니다.

프로그래밍을 잠시 배운 사람이라도 하위 프로세스 의 개념이 모호해 보일 수 있습니다. 이 기사에서는 하위 프로세스의 주요 개념과 Python 하위 프로세스 표준 라이브러리를 사용하는 방법을 자세히 살펴봅니다.

이 튜토리얼을 마치면 다음을 수행하게 됩니다.

  • 하위 프로세스의 개념 이해
  • Python 하위 프로세스 라이브러리의 기본 사항을 배웠습니다.
  • 유용한 예를 통해 Python 기술을 연습했습니다.

그 속으로 들어가 보자

하위 프로세스의 개념

일반적으로 하위 프로세스는 다른 프로세스에 의해 생성된 컴퓨터 프로세스입니다.

하위 프로세스는 각 상위 프로세스 뒤에 실행 중인 하위 프로세스가 있는 트리로 생각할 수 있습니다. 이것이 상당히 혼란스러울 수 있다는 것을 알고 있지만 간단한 그래픽으로 봅시다.

컴퓨터에서 실행 중인 프로세스를 시각화할 수 있는 몇 가지 방법이 있습니다. 예를 들어 UNIX(Linux 및 MAC)에는 대화형 프로세스 뷰어인 htop이 있습니다.

Htop 프로세스 뷰어

트리 모드 는 실행 중인 하위 프로세스를 살펴보는 데 가장 유용한 도구입니다. F5 로 활성화할 수 있습니다.

명령 섹션을 자세히 살펴보면 컴퓨터에서 실행 중인 프로세스의 구조를 확인할 수 있습니다.

Htop 공정 구조
모두 /sbin/init 로 시작합니다. 이는 컴퓨터의 각 프로세스를 시작하는 명령입니다. 그 시점에서 우리는 xfce4-screenshoterxfce4-terminal 과 같은 다른 프로세스의 시작을 볼 수 있습니다(더 많은 하위 프로세스에 도움이 됨)

Windows를 살펴보면 컴퓨터에서 충돌하는 프로그램을 종료할 때 유용한 결과를 가져오는 신화적인 작업 관리자가 있습니다.

Windows 작업 관리자

이제 우리는 수정처럼 명확한 개념을 갖게 되었습니다. Python에서 하위 프로세스를 구현하는 방법을 살펴보겠습니다.

Python의 하위 프로세스

Python의 하위 프로세스는 Python 스크립트가 운영 체제(OS)에 위임하는 작업입니다.

하위 프로세스 라이브러리를 사용하면 Python에서 직접 하위 프로세스를 실행하고 관리할 수 있습니다. 여기에는 표준 입력 stdin , 표준 출력 stdout 및 반환 코드 작업이 포함됩니다.

Python 표준 라이브러리의 일부이기 때문에 PIP로 설치할 필요가 없습니다.

따라서 모듈을 가져오기만 하면 파이썬에서 하위 프로세스를 사용할 수 있습니다.

 import subprocess # Using the module ....

참고: 이 기사를 따르려면 Python 3.5 +

현재 가지고 있는 파이썬 버전을 확인하려면 실행하면 됩니다.

 ❯ python --version Python 3.9.5 # My result

얻는 Python 버전이 2.x인 경우 다음 명령을 사용할 수 있습니다.

 python3 --version

계속해서 주제에 따라 하위 프로세스 라이브러리의 기본 아이디어는 Python 인터프리터에서 직접 원하는 명령을 실행하여 OS와 상호 작용할 수 있다는 것입니다.

즉, OS가 허용하는 한(그리고 루트 파일 시스템을 제거하지 않는 한) 원하는 모든 작업을 수행할 수 있습니다.

현재 디렉터리의 파일을 나열하는 간단한 스크립트를 만들어 사용하는 방법을 살펴보겠습니다.

첫 번째 하위 프로세스 응용 프로그램

먼저 list_dir.py 파일을 생성해 보겠습니다 . 이것은 목록 파일을 실험할 파일입니다.

 touch list_dir.py

이제 해당 파일을 열고 다음 코드를 사용하겠습니다.

 import subprocess subprocess.run('ls')

먼저 하위 프로세스 모듈을 가져온 다음 실행 되는 함수 run 을 사용하여 인수로 전달한 명령을 사용합니다.

이 함수는 subprocess.Popen에 대한 친숙한 바로 가기로 Python 3.5에서 도입되었습니다. subprocess.run 함수를 사용하면 나중에 통신을 호출할 수 있는 옵션이 있는 Popen과 달리 명령을 실행하고 완료될 때까지 기다릴 수 있습니다.

코드 출력에 대해 말하면 ls 는 현재 디렉토리의 파일을 나열하는 UNIX 명령입니다. 따라서 이 명령을 실행하면 현재 디렉토리에 있는 파일 목록이 표시됩니다.

 ❯ python list_dir.py example.py LICENSE list_dir.py README.md

참고: Windows를 사용하는 경우 다른 명령을 사용해야 한다는 점을 고려하십시오. 예를 들어 "ls" 를 사용하는 대신 "dir"을 사용할 수 있습니다.

이것은 너무 단순해 보일 수 있으며 당신이 옳습니다. 쉘이 제공하는 모든 기능에 대한 완전한 접근을 원합니다. 이제 subprocess를 사용하여 쉘에 인수를 전달하는 방법을 알아보겠습니다.

예를 들어 숨김 파일(점으로 시작하는 파일)도 나열하고 파일의 모든 메타데이터도 나열하려면 다음 코드를 작성합니다.

 import subprocess # subprocess.run('ls') # Simple command subprocess.run('ls -la', shell=True)

이 명령을 문자열로 실행하고 인수 shell 을 사용합니다. 즉, 하위 프로세스 실행이 시작될 때 셸을 호출하고 명령 인수가 셸에서 직접 해석됩니다.

그러나 shell=True를 사용하면 많은 단점이 있으며 최악의 경우 보안 누출 가능성이 있습니다. 공식 문서에서 이에 대해 읽을 수 있습니다.

실행 기능에 명령을 전달하는 가장 좋은 방법은 lst[0] 이 호출할 명령(이 경우 ls)이고 lst[n] 이 해당 명령의 인수인 목록을 사용하는 것입니다.

그렇게 하면 코드가 다음과 같이 보일 것입니다.

 import subprocess # subprocess.run('ls') # Simple command # subprocess.run('ls -la', shell=True) # Dangerous command subprocess.run(['ls', '-la'])

하위 프로세스의 표준 출력을 변수에 저장하려면 capture_output 인수를 true로 설정하면 됩니다.

 list_of_files = subprocess.run(['ls', '-la'], capture_output=True) print(list_of_files.stdout) ❯ python list_dir.py b'total 36\ndrwxr-xr-x 3 daniel daniel 4096 may 20 21:08 .\ndrwx------ 30 daniel daniel 4096 may 20 18:03 ..\n-rw-r--r-- 1 daniel daniel 55 may 20 20:18 example.py\ndrwxr-xr-x 8 daniel daniel 4096 may 20 17:31 .git\n-rw-r--r-- 1 daniel daniel 2160 may 17 22:23 .gitignore\n-rw-r--r-- 1 daniel daniel 271 may 20 19:53 internet_checker.py\n-rw-r--r-- 1 daniel daniel 1076 may 17 22:23 LICENSE\n-rw-r--r-- 1 daniel daniel 216 may 20 22:12 list_dir.py\n-rw-r--r-- 1 daniel daniel 22 may 17 22:23 README.md\n'

프로세스의 출력에 액세스하기 위해 인스턴스 속성 stdout 을 사용합니다.

이 경우 출력을 바이트 대신 문자열로 저장하려고 하며 텍스트 인수를 true로 설정하여 그렇게 할 수 있습니다.

 list_of_files = subprocess.run(['ls', '-la'], capture_output=True, text=True) print(list_of_files.stdout) ❯ python list_dir.py total 36 drwxr-xr-x 3 daniel daniel 4096 may 20 21:08 . drwx------ 30 daniel daniel 4096 may 20 18:03 .. -rw-r--r-- 1 daniel daniel 55 may 20 20:18 example.py drwxr-xr-x 8 daniel daniel 4096 may 20 17:31 .git -rw-r--r-- 1 daniel daniel 2160 may 17 22:23 .gitignore -rw-r--r-- 1 daniel daniel 271 may 20 19:53 internet_checker.py -rw-r--r-- 1 daniel daniel 1076 may 17 22:23 LICENSE -rw-r--r-- 1 daniel daniel 227 may 20 22:14 list_dir.py -rw-r--r-- 1 daniel daniel 22 may 17 22:23 README.md

완벽합니다. 이제 하위 프로세스 라이브러리의 기본 사항을 알았으므로 몇 가지 사용 예제로 넘어갈 차례입니다.

Python의 하위 프로세스 사용 예

이 섹션에서는 하위 프로세스 라이브러리의 몇 가지 실용적인 사용을 검토할 것입니다. 이 Github 저장소에서 모두 확인할 수 있습니다.

프로그램 검사기

이 라이브러리의 주요 용도 중 하나는 간단한 OS 작업을 수행하는 기능입니다.

예를 들어 프로그램이 설치되어 있는지 확인하는 간단한 스크립트입니다. Linux에서는 which 명령으로 이를 수행할 수 있습니다.

 '''Program checker with subprocess''' import subprocess program = 'git' process = subprocess. run(['which', program], capture_output=True, text=True) if process.returncode == 0: print(f'The program "{program}" is installed') print(f'The location of the binary is: {process.stdout}') else: print(f'Sorry the {program} is not installed') print(process.stderr)

참고: UNIX에서 명령이 성공하면 상태 코드는 0입니다. 그렇지 않으면 실행 중에 문제가 발생했습니다.

shell=True 인수를 사용하지 않기 때문에 사용자 입력을 안전하게 받을 수 있습니다. 또한 입력이 정규식 패턴으로 유효한 프로그램인지 확인할 수 있습니다.

 import subprocess import re programs = input('Separe the programs with a space: ').split() secure_pattern = '[\w\d]' for program in programs: if not re.match(secure_pattern, program): print("Sorry we can't check that program") continue process = subprocess. run( ['which', program], capture_output=True, text=True) if process.returncode == 0: print(f'The program "{program}" is installed') print(f'The location of the binary is: {process.stdout}') else: print(f'Sorry the {program} is not installed') print(process.stderr) print('\n')

이 경우 사용자로부터 프로그램을 받고 프로그램 문자열이 문자와 숫자만 포함함을 인증하는 정규식 표현식을 사용합니다. for 루프를 사용하여 각 프로그램의 존재를 확인합니다.

Python의 간단한 Grep

친구 Tom 은 텍스트 파일에 패턴 목록이 있고 각 패턴에 대한 일치 수를 얻으려는 또 다른 큰 파일이 있습니다. 그는 모든 패턴에 대해 grep 명령을 실행하는 데 몇 시간을 보냈습니다.

다행히 Python으로 이 문제를 해결하는 방법을 알고 있으며 몇 초 안에 이 작업을 완료하도록 도와줄 것입니다.

 import subprocess patterns_file = 'patterns.txt' readfile = 'romeo-full.txt' with open(patterns_file, 'r') as f: for pattern in f: pattern = pattern.strip() process = subprocess.run( ['grep', '-c', f'{pattern}', readfile], capture_output=True, text=True) if int(process.stdout) == 0: print( f'The pattern "{pattern}" did not match any line of {readfile}') continue print(f'The pattern "{pattern}" matched {process.stdout.strip()} times')

이 파일을 살펴보면서 작업하려는 파일 이름인 두 개의 변수를 정의합니다. 그런 다음 모든 패턴이 포함된 파일을 열고 반복합니다. 다음으로 "-c" 플래그(count를 의미)와 함께 grep 명령을 실행하는 하위 프로세스를 호출하고 조건부로 일치 결과를 결정합니다.

이 파일을 실행하면(Github 저장소에서 텍스트 파일을 다운로드할 수 있음을 기억하십시오)

하위 프로세스로 virtualenv 설정

Python으로 할 수 있는 가장 멋진 일 중 하나는 프로세스 자동화입니다. 이러한 종류의 스크립트는 일주일에 몇 시간을 절약할 수 있습니다.

예를 들어, 가상 환경을 생성하고 모든 종속성을 설치하기 위해 현재 디렉토리에서 requirements.txt 파일을 찾으려고 시도하는 설정 스크립트를 생성할 것입니다.

 import subprocess from pathlib import Path VENV_NAME = '.venv' REQUIREMENTS = 'requirements.txt' process1 = subprocess.run(['which', 'python3'], capture_output=True, text=True) if process1.returncode != 0: raise OSError('Sorry python3 is not installed') python_bin = process1.stdout.strip() print(f'Python found in: {python_bin}') process2 = subprocess.run('echo "$SHELL"', shell=True, capture_output=True, text=True) shell_bin = process2.stdout.split('/')[-1] create_venv = subprocess.run([python_bin, '-m', 'venv', VENV_NAME], check=True) if create_venv.returncode == 0: print(f'Your venv {VENV_NAME} has been created') pip_bin = f'{VENV_NAME}/bin/pip3' if Path(REQUIREMENTS).exists(): print(f'Requirements file "{REQUIREMENTS}" found') print('Installing requirements') subprocess.run([pip_bin, 'install', '-r', REQUIREMENTS]) print('Process completed! Now activate your environment with "source .venv/bin/activate"') else: print("No requirements specified ...")

이 경우 여러 프로세스를 사용하고 Python 스크립트에 필요한 데이터를 구문 분석합니다. 우리는 또한 requirements.txt 파일이 존재하는지 파악할 수 있도록 하는 pathlib 라이브러리를 사용하고 있습니다.

python 파일을 실행하면 OS에서 무슨 일이 일어나고 있는지에 대한 몇 가지 유용한 메시지를 받게 됩니다.

 ❯ python setup.py Python found in: /usr/bin/python3 Your venv .venv has been created Requirements file "requirements.txt" found Installing requirements Collecting asgiref==3.3.4 ....... Process completed! Now activate your environment with "source .venv/bin/activate"

표준 출력을 변수로 리디렉션하지 않기 때문에 설치 프로세스에서 출력을 얻습니다.

다른 프로그래밍 언어 실행

파이썬으로 다른 프로그래밍 언어를 실행하고 해당 파일에서 출력을 얻을 수 있습니다. 이는 하위 프로세스가 운영 체제와 직접 상호 작용하기 때문에 가능합니다.

예를 들어, C++와 Java로 hello world 프로그램을 만들어 봅시다. 다음 파일을 실행하려면 C++ 및 Java 컴파일러를 설치해야 합니다.

안녕하세요.cpp

 #include <iostream> int main(){ std::cout << "This is a hello world in C++" << std::endl; return 0; }


안녕하세요.자바

 class HelloWorld{ public static void main(String args[]){ System.out.println("This is a hello world in Java"); } }


간단한 Python 한 줄짜리 코드에 비해 이것이 많은 코드로 보인다는 것을 알고 있지만 이것은 단지 테스트 목적을 위한 것입니다.

디렉터리에서 모든 C++ 및 Java 파일을 실행하는 Python 스크립트를 만들 것입니다. 이를 위해 먼저 파일 확장자에 따라 파일 목록을 얻고자 하며 glob을 사용하면 쉽게 할 수 있습니다!

 from glob import glob # Gets files with each extension java_files = glob('*.java') cpp_files = glob('*.cpp')

그런 다음 하위 프로세스를 사용하여 각 유형의 파일을 실행할 수 있습니다.

 for file in cpp_files: process = subprocess.run(f'g++ {file} -o out; ./out', shell=True, capture_output=True, text=True) output = process.stdout.strip() + ' BTW this was runned by Python' print(output) for file in java_files: without_ext = file.strip('.java') process = subprocess.run(f'java {file}; java {without_ext}',shell=True, capture_output=True, text=True) output = process.stdout.strip() + ' A Python subprocess runned this :)' print(output)

한 가지 작은 트릭은 문자열 함수 스트립 을 사용하여 출력을 수정하고 필요한 것만 가져오는 것입니다.

참고: 대용량 Java 또는 C++ 파일은 메모리에 출력을 로드하고 있으며 이로 인해 메모리 누수가 발생할 수 있으므로 주의해서 실행하십시오.

외부 프로그램 열기

하위 프로세스를 통해 바이너리 위치를 호출하는 것만으로 다른 프로그램을 실행할 수 있습니다.

내가 선호하는 웹 브라우저인 브레이브 를 열어서 사용해 봅시다.

 import subprocess subprocess.run('brave')

이렇게 하면 브라우저 인스턴스가 열리거나 이미 브라우저를 실행하고 있는 경우 다른 탭만 열립니다.

열린 브라우저

플래그를 허용하는 다른 프로그램과 마찬가지로 플래그를 사용하여 원하는 동작을 생성할 수 있습니다.

 import subprocess subprocess.run(['brave', '--incognito'])

시크릿 플래그

요약하자면

하위 프로세스는 다른 프로세스에 의해 생성된 컴퓨터 프로세스입니다. htop 및 작업 관리자와 같은 도구를 사용하여 컴퓨터에서 실행 중인 프로세스를 확인할 수 있습니다.

Python에는 하위 프로세스와 함께 작동하는 자체 라이브러리가 있습니다. 현재 실행 기능은 하위 프로세스를 만들고 관리하기 위한 간단한 인터페이스를 제공합니다.

OS와 직접 상호 작용하기 때문에 어떤 종류의 응용 프로그램도 만들 수 있습니다.

마지막으로, 학습하는 가장 좋은 방법은 사용하고 싶은 것을 만드는 것임을 기억하십시오.