目次
1. Python의 subprocess 모듈이란
개요
Python의subprocess
모듈은 시스템 명령어나 외부 프로그램을 Python에서 실행하기 위한 강력한 도구입니다. 이 모듈을 사용하면 표준 입출력 및 프로세스 관리가 가능해져 Python 프로그램과 외부 프로그램의 연동을 쉽게 할 수 있습니다. 기존의 os.system()
이나 commands
모듈을 대체하는 방법으로, 보다 안전하고 유연한 프로세스 제어를 제공합니다.주요 용도
- 셸 명령 실행: 간단한 시스템 명령 호출。
- 프로세스 관리: 외부 프로그램 실행 및 표준 입출력 리다이렉션。
- 비동기 처리: 장시간 걸리는 작업이나 병렬로 실행되는 작업 관리。
2. 기본적인 사용법:subprocess.run()
기본 사용법
subprocess.run()
은 시스템 명령을 Python 내부에서 간단히 실행하기 위한 함수입니다. 예를 들어, 디렉터리 내 파일을 목록화하려면 다음과 같은 코드를 사용합니다。import subprocess
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)
이 코드는 ls -l
명령을 실행하고, 그 출력을 stdout
에 저장하여 Python에서 처리합니다. capture_output=True
를 통해 표준 출력을 캡처하고, text=True
로 결과를 문자열로 다룰 수 있습니다。에러 핸들링
subprocess.run()
을 사용하면, 명령이 실패했을 때 stderr
를 이용해 오류 메시지를 얻을 수 있습니다. 또한 returncode
로 실행 성공 여부를 확인할 수 있습니다。result = subprocess.run(['ls', 'nonexistentfile'], capture_output=True, text=True)
if result.returncode != 0:
print(f"오류: {result.stderr}")
이 예에서는 존재하지 않는 파일을 지정하면 표준 오류에 오류 메시지가 표시됩니다。3. 비동기 실행: subprocess.Popen()
Popen
을 사용한 비동기 처리
subprocess.run()
은 동기 처리이므로, 명령이 종료될 때까지 Python 프로그램은 다음 처리로 진행할 수 없지만, subprocess.Popen()
을 사용하면 비동기로 프로세스를 실행할 수 있어 다른 작업을 동시에 수행할 수 있습니다。import subprocess
proc = subprocess.Popen(['sleep', '5'], stdout=subprocess.PIPE)
print("프로세스가 시작되었습니다")
proc.wait()
print("프로세스가 종료되었습니다")
이 코드에서는 sleep 5
가 비동기로 실행되어 그 동안 다른 작업을 진행할 수 있습니다。표준 입출력 제어
Popen
에서는 표준 입출력 리다이렉트를 세밀하게 제어할 수 있습니다. 예를 들어, 다음 코드는 파일에서 데이터를 읽어 cat
명령으로 처리하고, 다른 파일에 기록하는 예시입니다。with open('input.txt', 'r') as infile, open('output.txt', 'w') as outfile:
proc = subprocess.Popen(['cat'], stdin=infile, stdout=outfile)
proc.wait()
이를 통해 외부 명령의 표준 입력 및 출력을 파일에 리다이렉트하여 처리할 수 있습니다。4. 사용 예시: 자동화 스크립트
파일 백업
시스템 관리 및 정기적인 작업 자동화에subprocess
는 매우 편리합니다. 예를 들어, 다음 예에서는 파일을 백업 디렉터리로 자동으로 복사합니다。import subprocess
files_to_backup = ['file1.txt', 'file2.txt', 'file3.txt']
backup_dir = '/backup/directory/'
for file in files_to_backup:
subprocess.run(['cp', file, backup_dir])
이 코드는 지정된 파일을 백업 폴더에 복사합니다. 이렇게 간단한 스크립트를 작성함으로써 정기적인 백업 작업을 자동화할 수 있습니다。CI/CD 파이프라인에서의 활용
subprocess
는 지속적인 통합(CI) 및 지속적인 배포(CD) 환경에서도 사용되며, 테스트 스크립트의 자동 실행이나 배포 처리의 일부로 통합됩니다. 예를 들어, 테스트 스크립트를 실행하고 성공하면 다음 단계로 진행하는 식의 자동화가 가능합니다。
5. 보안 및 베스트 프랙티스
shell=True
의 위험
shell=True
옵션은 쉘을 통해 명령을 실행할 때 사용하지만 보안상의 위험이 따릅니다. 특히 외부 입력을 그대로 전달하는 경우 쉘 인젝션 공격 위험이 있습니다. shell=False
를 사용하면 이 위험을 완화할 수 있습니다。import subprocess
# 권장되는 사용법(안전)
subprocess.run(['ls', '-l'])
# shell=True(주의 필요)
subprocess.run('ls -l', shell=True)
크로스 플랫폼 지원
시스템 명령은 서로 다른 OS 환경에서 다른 명령을 사용할 수 있습니다. 다음과 같이 Python의platform
모듈을 사용하여 실행할 명령을 OS에 따라 전환할 수 있습니다。import platform
import subprocess
if platform.system() == "Windows":
subprocess.run(['dir'], shell=True)
else:
subprocess.run(['ls', '-l'])
6. 트러블슈팅 및 디버깅
일반적인 오류와 대책
subprocess
를 사용할 때, 파일을 찾을 수 없거나 접근 권한이 없는 등의 오류가 자주 발생합니다. 이러한 오류는 stderr
를 사용해 캡처하고, returncode
를 확인함으로써 오류 상세 정보를 얻을 수 있습니다。디버깅을 위한 팁
check=True
옵션을 사용하면, 명령이 실패했을 때 예외를 발생시켜 문제를 조기에 감지할 수 있습니다. 또한, 표준 출력과 오류 메시지를 캡처하여 로그에 남김으로써 디버깅이 쉬워집니다。import subprocess
try:
result = subprocess.run(['ls', '-l'], check=True, capture_output=True, text=True)
print(result.stdout)
except subprocess.CalledProcessError as e:
print(f"오류가 발생했습니다: {e}")
7. 비동기 처리와 asyncio와의 연동
asyncio를 사용한 비동기 처리
asyncio
를 사용하면 subprocess
와 연동하여 여러 프로세스를 병렬로 비동기 처리할 수 있습니다. 다음 예시는 asyncio
를 사용해 ls
명령을 비동기적으로 실행하고 결과를 캡처합니다。import asyncio
import subprocess
async def run_command():
proc = await asyncio.create_subprocess_exec('ls', '-l',
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)
stdout, stderr = await proc.communicate()
if stdout:
print(f'[stdout]n{stdout.decode()}')
if stderr:
print(f'[stderr]n{stderr.decode()}')
asyncio.run(run_command())
이 코드는 비동기로 명령을 실행하고 표준 출력 및 표준 오류의 결과를 처리합니다. asyncio
를 사용하면 비동기 태스크를 효율적으로 관리할 수 있습니다.