pty — 의사 터미널 유틸리티

pty — 의사 터미널 유틸리티

pty 모듈은 의사 터미널(pseudo-terminal) 개념을 다루는 연산을 정의해요. 다른 프로세스를 시작하고 그 제어 터미널에 프로그램적으로 쓰고 읽을 수 있게 해줘요.

출처: Python documentation

본문

가용성: Unix. 의사 터미널 처리는 플랫폼에 크게 의존해요. 이 코드는 주로 Linux, FreeBSD, macOS 에서 테스트됐어요(다른 POSIX 플랫폼에서도 동작해야 하지만 철저히 테스트되진 않았어요).

함수 (Functions)

  • pty.fork() — fork. 자식의 제어 터미널을 의사 터미널에 연결해요. 반환 값은 (pid, fd) 이에요. 자식은 pid 가 0이고 fd유효하지 않아요. 부모의 반환 값은 자식의 pid 이고, fd 는 자식의 제어 터미널(그리고 자식의 표준 입력·출력)에 연결된 파일 디스크립터예요.
    • ⚠️ 경고: macOS 에서 이 함수를 더 높은 레벨 시스템 API와 섞어 쓰는 것은 안전하지 않아요. 여기에는 urllib.request 사용도 포함돼요.
  • pty.openpty() — 가능하면 os.openpty() 를, 아니면 일반 Unix 시스템용 에뮬레이션 코드를 사용해 새 의사 터미널 쌍을 열어요. 마스터와 슬레이브 끝에 대한 파일 디스크립터 쌍 (master, slave) 를 반환해요.
  • pty.spawn(argv[, master_read[, stdin_read]] — 프로세스를 생성하고 그 제어 터미널을 현재 프로세스의 표준 입출력에 연결해요. 제어 터미널에서 읽으라고 하는 프로그램을 막을 때 자주 쓰여요. pty 뒤에 생성된 프로세스가 결국 종료될 것으로 예상되며, 종료되면 spawn 이 반환돼요.
    • 루프가 현재 프로세스의 STDIN 을 자식에게, 자식에서 받은 데이터를 현재 프로세스의 STDOUT 으로 복사해요.
    • master_readstdin_read 함수는 읽을 파일 디스크립터를 받고 항상 바이트 문자열을 반환해야 해요. 자식 프로세스가 종료되기 전에 spawn 이 반환되게 하려면 빈 바이트 배열을 반환해 파일 끝을 알려요.
    • 두 함수의 기본 구현은 호출마다 최대 1024 바이트를 읽고 반환해요.
    • 두 콜백 중 하나에서 빈 바이트 문자열을 반환하면 EOF 로 해석되고 그 콜백은 이후 호출되지 않아요.
    • 자식 프로세스에 대한 os.waitpid() 의 종료 상태 값을 반환해요. os.waitstatus_to_exitcode() 로 종료 상태를 종료 코드로 변환할 수 있어요. pty.spawn 감사 이벤트를 인자 argv 로 발생시켜요.
    • 버전 3.4에서 spawn() 이 자식 프로세스의 os.waitpid() 상태 값을 반환하도록 변경됐어요.

예제 (Example)

다음 프로그램은 의사 터미널을 사용해 터미널 세션의 모든 입력·출력을 "typescript"에 기록하는 Unix 명령 script(1) 처럼 동작해요.

import argparse
import os
import pty
import sys
import time

parser = argparse.ArgumentParser()
parser.add_argument('-a', dest='append', action='store_true')
parser.add_argument('-p', dest='use_python', action='store_true')
parser.add_argument('filename', nargs='?', default='typescript')
options = parser.parse_args()

shell = sys.executable if options.use_python else os.environ.get('SHELL', 'sh')
filename = options.filename
mode = 'ab' if options.append else 'wb'

with open(filename, mode) as script:
    def read(fd):
        data = os.read(fd, 1024)
        script.write(data)
        return data

    print('Script started, file is', filename)
    script.write(('Script started on %s\n' % time.asctime()).encode())

    pty.spawn(shell, read)

    script.write(('Script done on %s\n' % time.asctime()).encode())
    print('Script done, file is', filename)

더 알아보기 (Learn more)