cmd — 줄 단위 명령 해석기 지원
cmd — 줄 단위 명령 해석기 지원
(소스: Lib/cmd.py)
Cmd 클래스는 줄 단위 명령 해석기(line-oriented command interpreter) 를 작성하기 위한 간단한 프레임워크를 제공해요. 테스트 하네스, 관리 도구, 그리고 나중에 더 정교한 인터페이스로 감쌀 프로토타입에서 자주 유용해요.
본문
class cmd.Cmd(completekey='tab', stdin=None, stdout=None)
Cmd 인스턴스 또는 서브클래스 인스턴스는 줄 단위 인터프리터 프레임워크예요. Cmd 자체를 인스턴스화할 이유는 없고, Cmd의 메서드를 상속받아 액션 메서드를 캡슐화하기 위해 직접 정의하는 인터프리터 클래스의 수퍼클래스로 유용해요.
선택적 인자 completekey는 완성(completion) 키의 readline 이름이고 기본은 Tab이에요. completekey가 None이 아니고 readline을 사용할 수 있으면 명령 완성이 자동으로 이뤄져요. 기본 'tab'은 특별하게 처리돼서 모든 readline.backend에서 Tab 키를 가리켜요. 구체적으로 readline.backend가 editline이면 Cmd는 'tab' 대신 '^I'을 사용해요. 다른 값들은 이렇게 처리되지 않고 특정 백엔드에서만 동작할 수 있어요.
선택적 인자 stdin과 stdout은 Cmd 인스턴스가 입력·출력에 사용할 파일 객체를 지정해요. 지정하지 않으면 각각 sys.stdin과 sys.stdout로 기본 설정돼요. 주어진 stdin을 쓰고 싶다면 인스턴스의 use_rawinput 속성을 False로 설정해야 해요. 아니면 stdin이 무시돼요.
Cmd 객체
Cmd 인스턴스는 다음 메서드를 가져요.
Cmd.cmdloop(intro=None): 프롬프트를 반복해서 내고 입력을 받고, 받은 입력에서 초기 접두사를 파싱해 액션 메서드로 디스패치하며 줄의 나머지를 인자로 전달해요. 선택적 인자는 첫 프롬프트 전에 내는 배너/intro 문자열 (intro 클래스 속성 덮어씀). readline 모듈이 로드되면 입력이 자동으로 bash 같은 히스토리 편집을 상속받아요. 입력의 파일 끝은 'EOF' 문자열로 전달돼요. 인터프리터 인스턴스는do_foo()메서드가 있을 때만 명령 이름 foo를 인식해요. 특수하게 '?'로 시작하는 줄은do_help()메서드로, '!'로 시작하는 줄은do_shell()메서드(정의된 경우)로 디스패치돼요.postcmd()메서드가 true 값을 반환하면 이 메서드는 반환해요. 완성이 활성화되면 명령 완성이 자동으로 이뤄지고, 명령 인자 완성은complete_foo(text, line, begidx, endidx)를 호출해서 해요.Cmd.do_help(arg): 모든 Cmd 서브클래스는 미리 정의된do_help()를 상속받아요. 'bar' 인자로 호출하면help_bar()메서드를 호출하고, 없으면do_bar()의 docstring(있으면)을 출력해요. 인자 없이do_help()는 사용 가능한 모든 도움말 토픽과 문서화되지 않은 명령을 나열해요.Cmd.onecmd(str): 인자를 프롬프트에 응답으로 입력된 것처럼 해석해요. 오버라이드할 수 있지만 보통 필요 없어요. 반환값은 명령 해석이 멈춰야 하는지를 나타내는 플래그예요. 명령에 대응하는do_*()메서드가 있으면 그 반환값을, 아니면default()의 반환값을 반환해요.Cmd.emptyline(): 프롬프트에 빈 줄이 입력됐을 때 호출. 오버라이드하지 않으면 마지막 비어 있지 않은 명령을 반복해요.Cmd.default(line): 명령 접두사가 인식되지 않는 입력 줄에서 호출. 오버라이드하지 않으면 오류 메시지를 출력하고 반환해요.Cmd.completedefault(text, line, begidx, endidx): 명령 특정complete_*()메서드가 없을 때 입력 줄 완성을 위해 호출. 기본은 빈 리스트 반환.Cmd.columnize(list, displaywidth=80): 문자열 리스트를 컴팩트한 열 집합으로 표시하기 위해 호출. 각 열은 필요한 만큼만 넓고, 가독성을 위해 두 칸 공백으로 구분돼요.Cmd.precmd(line): 명령 줄이 해석되기 직전, 입력 프롬프트가 생성·발행된 후 실행되는 훅 메서드.Cmd의 스텁으로 서브클래스가 오버라이드하도록 존재. 반환값은onecmd()가 실행할 명령으로 쓰여요. precmd 구현이 명령을 다시 쓰거나 line을 그대로 반환할 수 있어요.Cmd.postcmd(stop, line): 명령 디스패치가 끝난 직후 실행되는 훅 메서드. line은 실행된 명령 줄, stop은 postcmd() 호출 후 실행이 종료될지 나타내는 플래그(onecmd()의 반환값). 이 메서드의 반환값은 stop에 해당하는 내부 플래그의 새 값으로 쓰이고, false를 반환하면 해석이 계속돼요.Cmd.preloop():cmdloop()가 호출될 때 한 번 실행되는 훅 메서드 (스텁).Cmd.postloop():cmdloop()가 반환하려 할 때 한 번 실행되는 훅 메서드 (스텁).
Cmd 서브클래스의 인스턴스는 공개 인스턴스 변수도 가져요.
Cmd.prompt: 입력을 요청하기 위해 내는 프롬프트.Cmd.identchars: 명령 접두사에 받아들여지는 문자 문자열.Cmd.lastcmd: 마지막으로 본 비어 있지 않은 명령 접두사.Cmd.cmdqueue: 큐에 넣은 입력 줄의 리스트.cmdloop()에서 새 입력이 필요할 때 확인되고, 비어 있지 않으면 프롬프트에 입력된 것처럼 순서대로 처리돼요.Cmd.intro: intro/banner로 내는 문자열.cmdloop()에 인자를 주어 덮어쓸 수 있어요.Cmd.doc_header: 도움말 출력에 문서화된 명령 섹션이 있으면 내는 헤더.Cmd.misc_header: 도움말 출력에 기타 도움말 토픽 섹션(대응하는do_*()없는help_*()메서드)이 있으면 내는 헤더.Cmd.undoc_header: 도움말 출력에 문서화되지 않은 명령 섹션(대응하는help_*()없는do_*()메서드)이 있으면 내는 헤더.Cmd.ruler: 도움말 메시지 헤더 아래 구분선을 그리는 데 쓰는 문자. 비어 있으면 구분선을 안 그려요. 기본 '='.Cmd.use_rawinput: 기본 true 플래그. true면cmdloop()는input()을 사용해 프롬프트를 표시하고 다음 명령을 읽어요. false면sys.stdout.write()와sys.stdin.readline()을 사용해요.
Cmd 예제
cmd 모듈은 주로 사용자가 프로그램과 대화형으로 작업하게 하는 커스텀 셸을 만드는 데 유용해요. 예제는 turtle 모듈의 몇 가지 명령 주위에 셸을 만드는 방법을 보여줘요. forward() 같은 기본 turtle 명령은 do_forward()라는 메서드로 Cmd 서브클래스에 추가돼요. 인자는 숫자로 변환돼 turtle 모듈로 디스패치되고, docstring이 셸의 도움말 유틸리티에 사용돼요. precmd() 메서드로 기록·재생 기능도 구현돼요.
import cmd, sys
from turtle import *
class TurtleShell(cmd.Cmd):
intro = 'Welcome to the turtle shell. Type help or ? to list commands.\n'
prompt = '(turtle) '
file = None
def do_forward(self, arg):
'Move the turtle forward by the specified distance: FORWARD 10'
forward(*parse(arg))
# ... (다른 do_* 메서드들)
def precmd(self, line):
line = line.lower()
if self.file and 'playback' not in line:
print(line, file=self.file)
return line
def parse(arg):
'Convert a series of zero or more numbers to an argument tuple'
return tuple(map(int, arg.split()))
if __name__ == '__main__':
TurtleShell().cmdloop()