프로그래밍/Python

[python] 쉘의 파이프 "|"를 subprocess.Popne()으로 처리하는 방법

채윤아빠 2025. 4. 14. 16:35

개요

보안성 등을 높이기 위하여 shell=Falsesubprocess.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=Falsesubprocess.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.PIPEstdin=...을 이용해 파이프라인을 만듭니다.
  • .communicate()로 결과를 받아오며, decode()로 문자열로 변환합니다.

맺는말

subprocess 모듈은 단순한 명령 실행을 넘어서 파이프 연결, 입출력 제어 등 다양한 시스템 프로그래밍 작업을 가능하게 해줍니다.
보안상 이유로 shell=False로 외부 쉘 명령을 파이프를 구성하여 동작시키려면, subprocess.Popen()으로 파이프를 직접 구성해야 한다는 점이 핵심입니다.

파이프 명령이 필요할 때 subprocess.Popen()을 활용해 안전하고 유연하게 처리해 보시기 바랍니다. 감사합니다!



728x90
반응형