Python 하위 프로세스 실행 중 Stdout 읽기

Salman Mehmood 2023년10월8일
  1. Python 하위 프로세스 실행 중 stdout 읽기
  2. 접근법 1: Python에서 실행하는 동안 check_call을 사용하여 subprocessstdout 읽기
  3. 접근법 2: Python에서 실행하는 동안 subprocessstdout을 읽기 위해 프로세스를 폴링합니다.
Python 하위 프로세스 실행 중 Stdout 읽기

이 기사의 주요 목적은 Python에서 실행 중인 subprocessstdout을 읽는 방법을 보여주는 것입니다.

Python 하위 프로세스 실행 중 stdout 읽기

다른 많은 내장 모듈과 마찬가지로 Subprocess도 “일반” Python 설치와 함께 미리 설치된 내장 모듈입니다.

새 프로세스에서 작업, 프로세스 및 프로그램을 실행하고 특정 작업 집합을 수행하고 결과를 반환하려는 경우에 주로 사용됩니다.

널리 사용되는 많은 이유 중 하나는 별도의 프로세스로 프로그램에서 직접 외부 프로그램 및 실행 파일을 실행할 수 있다는 것입니다.

Subprocess 라이브러리를 사용하여 프로그램을 실행하는 동안 해당 외부 프로그램의 출력을 실시간으로 표시해야 할 수 있습니다. 이것은 프로그램이 실시간일 수 있고 짧은 시간 후에 계산에 의존하는 경우와 같은 많은 이유로 요구 사항이 될 수 있습니다.

다음 프로그램을 고려하십시오.

import subprocess


def execute(command):
    process = subprocess.Popen(
        command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
    )
    output = process.communicate()[0]
    exitCode = process.returncode

    if exitCode == 0:
        return output
    else:
        raise Exception(command, exitCode, output)


if __name__ == "__main__":
    print(execute("cd C:\\ && C: && tree").decode("unicode_escape"))

출력:

Folder PATH listing
Volume serial number is 0213-B7F2
C:.
+---DRIVERS
¦   +---bluetooth
¦       +---U1BLT07AVVASDSAP
¦           +---Custom
¦           ¦   +---EULA
¦           +---Win64
¦               +---LD
¦               +---svcpack
+---flutter
¦   +---.git
¦   ¦   +---hooks
¦   ¦   +---info
¦   ¦   +---logs
¦   ¦   ¦   +---refs
¦   ¦   ¦       +---heads
¦   ¦   ¦       +---remotes
¦   ¦   ¦           +---origin
¦   ¦   +---objects
¦   ¦   ¦   +---info
¦   ¦   ¦   +---pack
¦   ¦   +---refs
¦   ¦       +---heads
¦   ¦       +---remotes
¦   ¦       ¦   +---origin
¦   ¦       +---tags
¦   +---.github
¦   ¦   +---ISSUE_TEMPLATE
¦   ¦   +---workflows
¦   +---.idea
¦   ¦   +---runConfigurations
...

프로그램에서 출력을 볼 수 있지만 실시간으로는 볼 수 없습니다. 출력은 전체 명령(여기서는 tree)이 실행을 마친 후에만 표시됩니다.

Subprocess 명령을 사용하여 별도의 프로세스에서 프로그램(또는 명령)이 실행될 때까지 출력에 무언가가 표시되지 않습니다.

우리의 경우 실시간으로 출력을 얻어야 하므로 stdout에 기록된 프로그램의 출력을 보여주는 또 다른 솔루션을 만들어야 합니다.

솔루션은 여러 가지 방법으로 접근할 수 있으며 그 중 일부는 아래에 언급되어 있습니다.

접근법 1: Python에서 실행하는 동안 check_call을 사용하여 subprocessstdout 읽기

다음 코드를 고려하십시오.

import subprocess
import sys


def execute(command):
    subprocess.check_call(
        command, shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT
    )


if __name__ == "__main__":
    print(execute("cd C:\\ && C: && tree").decode("unicode_escape"))

출력:

Folder PATH listing
Volume serial number is 0213-B7F2
C:.
├───DRIVERS
│   └───bluetooth
│       └───U1BLT0720US14CMP
│           ├───Custom
│           │   └───EULA
│           └───Win64
│               ├───LD
│               └───svcpack
├───flutter
│   ├───.git
│   │   ├───hooks
│   │   ├───info
│   │   ├───logs
│   │   │   └───refs
│   │   │       ├───heads
│   │   │       └───remotes
│   │   │           └───origin
│   │   ├───objects
│   │   │   ├───info
│   │   │   └───pack
│   │   └───refs
│   │       ├───heads
│   │       ├───remotes
│   │       │   └───origin
│   │       └───tags
│   ├───.github
│   │   ├───ISSUE_TEMPLATE
│   │   └───workflows
│   ├───.idea
│   │   └───runConfigurations
│   ├───.pub-cache
│   │   ├───hosted
│   │   │   └───pub.dartlang.org
│   │   │       ├───.cache
...

주요 요구 사항이 프로그램의 출력을 실시간으로 인쇄하는 것이라면 check_call을 사용하여 이를 달성할 수 있습니다. 이 간단하고 깨끗하며 우아한 솔루션은 출력만 인쇄해야 하는 경우와 같이 매우 간단한 프로그램에 간결하고 “완벽"합니다.

check_call은 매개변수 전달도 지원하므로 프로그램이 작동하기 위해 인수가 필요한 경우 번거로움 없이 함수에 쉽게 전달할 수 있습니다. 이 메서드는 프로그램이 완료될 때까지 기다립니다.

프로그램 완료에 따라 메서드가 반환됩니다. 그렇지 않으면 CalledProcessError 예외가 발생합니다. CalledProcessError에는 returncode 특성을 사용하여 액세스할 수 있는 오류 반환 코드가 있습니다.

위에서 언급한 코드에서 command는 실행할 명령(또는 프로그램)이 포함된 check_call 메서드로 전달됩니다.

shell 매개변수는 셸을 사용하여 프로세스를 실행하기 위해 true로 설정되었고 프로세스의 stdout은 우리 프로그램의 stdout으로 설정되었으므로 stdout에 직접 기록할 수 있습니다. stdout에서 발생하는 변경 사항을 확인하십시오.

마지막으로 stderr는 생성된 프로세스의 stdout으로 설정됩니다.

접근법 2: Python에서 실행하는 동안 subprocessstdout을 읽기 위해 프로세스를 폴링합니다.

다음 코드를 고려하십시오.

import subprocess
import sys


def execute(command):
    process = subprocess.Popen(
        command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
    )

    # Poll process for new output until finished
    while True:
        nextline = process.stdout.readline().decode("unicode_escape")
        if nextline == "" and process.poll() is not None:
            break
            sys.stdout.write(nextline)
            sys.stdout.flush()

        output = process.communicate()[0]
        exitCode = process.returncode

        if exitCode == 0:
            return output
        else:
            raise Exception(command, exitCode, output)


if __name__ == "__main__":
    print(execute("cd C:\\ && C: && tree").decode("unicode_escape"))

출력:

...
¦   ¦   ¦       ¦   ¦       +---UuidUtil
¦   ¦   ¦       ¦   +---example
¦   ¦   ¦       ¦   +---lib
¦   ¦   ¦       ¦   +---test
¦   ¦   ¦       +---vector_math-2.1.2
¦   ¦   ¦       ¦   +---benchmark
¦   ¦   ¦       ¦   +---bin
¦   ¦   ¦       ¦   +---lib
¦   ¦   ¦       ¦   ¦   +---src
¦   ¦   ¦       ¦   ¦       +---vector_math
¦   ¦   ¦       ¦   ¦       ¦   +---third_party
¦   ¦   ¦       ¦   ¦       +---vector_math_64
¦   ¦   ¦       ¦   ¦       ¦   +---third_party
¦   ¦   ¦       ¦   ¦       +---vector_math_geometry
¦   ¦   ¦       ¦   ¦       ¦   +---filters
¦   ¦   ¦       ¦   ¦       ¦   +---generators
¦   ¦   ¦       ¦   ¦       +---vector_math_lists
¦   ¦   ¦       ¦   ¦       +---vector_math_operations
¦   ¦   ¦       ¦   +---test
¦   ¦   ¦       ¦   +---tool
¦   ¦   ¦       +---video_player-2.2.11
¦   ¦   ¦       ¦   +---android
¦   ¦   ¦       ¦   ¦   +---gradle
...

Subprocess를 사용하여 생성된 프로그램의 출력이 stdout에 기록되는 즉시 인쇄되도록 하려면 출력 프로세스를 폴링하고 프로그램 stdoutstdout의 마지막 줄을 계속 읽어야 합니다.

“무한” 루프에서 readline()을 사용하여 생성된 프로세스의 출력을 계속 읽습니다. 출력이 인코딩되었으므로 적절하게 표시되도록 디코딩해야 합니다(이 경우 utf-escape).

이는 decode 방법을 사용하고 관련 인코딩 체계를 전달하여 수행할 수 있습니다.

프로그램 실행이 완료되면 “무한” 루프도 탈출해야 합니다. 다음 두 가지를 확인하여 그렇게 할 수 있습니다.

  1. 현재 stdout 라인이 비어 있습니다.
  2. 프로세스가 종료되었거나 종료되었습니다.

첫 번째 조건에 대한 간단한 문자열 비교와 프로세스가 종료되었는지 여부를 확인하는 poll() 메서드를 사용하여 매우 간단하게 수행할 수 있습니다. 프로그램이 종료되면 returncode를 반환합니다. 그렇지 않으면 None을 반환합니다.

None과의 간단한 비교를 통해 프로그램 실행이 완료되었는지 여부에 대한 정보도 얻을 수 있습니다.

Salman Mehmood avatar Salman Mehmood avatar

Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.

LinkedIn

관련 문장 - Python Subprocess