[python] 쉘의 파이프 "|"를 subprocess.Popne()으로 처리하는 방법
개요
보안성 등을 높이기 위하여 shell=False
로 subprocess.run()
을 사용할 때는 쉘 기능이 비활성화되므로 "ls | grep txt"
같은 파이프라인 명령어를 문자열로 넘길 수 없습니다. 이번 글에서는 쉘에서 파이프로 여러 명령을 연결하여 처리하는 것을 파이썬으로 어떻게 구현하는지 알아보도록 하겠습니다.
기본적인 쉘 명령과 shell=True
예를 들어, 리눅스에서 다음과 같은 명령을 실행한다고 해볼까요?
ls | grep txt
이 명령은 현재 디렉토리에서 txt라는 문자열이 포함된 파일만 출력합니다. Python에서 이걸 단순히 실행하려면 shell=True로 아래와 같이 할 수 있습니다.
from subprocess import run
result = run("ls | grep txt", shell=True, capture_output=True, text=True)
print(result.stdout)
그런데... 왜 shell=False를 사용할까요?shell=True
는 편하지만 보안상 위험할 수 있습니다. 특히 사용자 입력을 포함하는 명령일 경우 쉘 인젝션(shell injection) 공격에 취약하므로, 가능한 한 shell=False
를 권장합니다.
프로세스 파이프 연결하기
보안성을 높이기 위하여 shell=False
로 subprocess.run()
을 사용할 때는 쉘 기능이 비활성화되므로, 이 것 대신 파이프라인을 명시적으로 subprocess를 연결하여 구현해야 합니다. 직접 파이프라인을 구성하기 위해서는 subprocess.Popne()
를 이용해야 합니다.
아래는 "ls | grep txt"
명령을 subprocess.Popne()
함수를 활용하여 shell=False
상태로 구현하는 예제입니다.
from subprocess import PIPE, Popne
# 첫 번째 명령: ls
p1 = Popen(["ls"], stdout=PIPE)
# 두 번째 명령: grep txt, 앞선 명령의 출력을 입력으로 사용
p2 = Popen(["grep", "txt"], stdin=p1.stdout, stdout=PIPE)
# p1의 stdout을 닫아서 리소스를 정리하고, 파이프가 닫혔음을 알림
p1.stdout.close()
# 결과 출력
output, error = p2.communicate()
print(output.decode())
요점 정리
shell=False
에서는 쉘의 기능(예:|
,&&
,;
)을 직접 사용할 수 없습니다.- 대신
subprocess.Popen()
으로 파이프를 직접 구성해야 합니다. stdout=subprocess.PIPE
와stdin=...
을 이용해 파이프라인을 만듭니다..communicate()
로 결과를 받아오며,decode()
로 문자열로 변환합니다.
맺는말
subprocess
모듈은 단순한 명령 실행을 넘어서 파이프 연결, 입출력 제어 등 다양한 시스템 프로그래밍 작업을 가능하게 해줍니다.
보안상 이유로 shell=False
로 외부 쉘 명령을 파이프를 구성하여 동작시키려면, subprocess.Popen()
으로 파이프를 직접 구성해야 한다는 점이 핵심입니다.
파이프 명령이 필요할 때 subprocess.Popen()을 활용해 안전하고 유연하게 처리해 보시기 바랍니다. 감사합니다!