cmd — 支持面向行的命令解释器

源代码: Lib/cmd.py


Cmd 类为编写面向行的命令解释器提供了一个简单的框架。它们通常对测试框架、管理工具和稍后将包装在更复杂界面中的原型很有用。

class cmd.Cmd(completekey='tab', stdin=None, stdout=None)

一个 Cmd 实例或子类实例是一个面向行的解释器框架。没有充分的理由实例化 Cmd 本身;相反,它可用作您自己定义的解释器类的超类,以继承 Cmd 的方法并封装操作方法。

可选参数 completekeyreadline 中完成键的名称;其默认值为 Tab。如果 completekey 不为 Nonereadline 可用,则会自动完成命令。

可选参数stdinstdout指定 Cmd 实例或子类实例用于输入和输出的输入和输出文件对象。如果未指定,它们将默认为 sys.stdinsys.stdout

如果您希望使用给定的stdin,请务必将实例的 use_rawinput 属性设置为 False,否则将忽略stdin

Cmd 对象

一个 Cmd 实例具有以下方法

Cmd.cmdloop(intro=None)

重复发出提示,接受输入,解析接收到的输入的初始前缀,并分派到操作方法,将行的其余部分作为参数传递给它们。

可选参数是在第一个提示之前发出的横幅或介绍字符串(这将覆盖 intro 类属性)。

如果加载了 readline 模块,输入将自动继承bash类历史列表编辑(例如,Control-P 滚动回上一个命令,Control-N 向前滚动到下一个命令,Control-F 将光标向右移动,不会破坏,Control-B 将光标向左移动,不会破坏,等等)。

输入结束时,将作为字符串 'EOF' 传回。

解释器实例将识别命令名称 foo,当且仅当它具有方法 do_foo()。作为特殊情况,以字符 '?' 开头的行将分派到方法 do_help()。作为另一个特殊情况,以字符 '!' 开头的行将分派到方法 do_shell()(如果定义了此类方法)。

postcmd() 方法返回真值时,此方法将返回。 postcmd()stop 参数是命令对应的 do_*() 方法的返回值。

如果启用自动完成,则将自动完成命令,并通过调用 complete_foo()(带有参数 textlinebegidxendidx)完成命令参数。text 是我们尝试匹配的字符串前缀:所有返回的匹配项都必须以它开头。line 是删除前导空格后的当前输入行,begidxendidx 是前缀文本的开始和结束索引,可用于根据参数所在的位置提供不同的完成。

Cmd.do_help(arg)

Cmd 的所有子类都继承一个预定义的 do_help()。此方法使用参数 'bar' 调用,调用相应的方法 help_bar(),如果不存在,则打印 do_bar() 的文档字符串(如果可用)。如果没有参数,do_help() 会列出所有可用的帮助主题(即,所有带有相应 help_*() 方法或具有文档字符串的命令),还会列出所有未记录的命令。

Cmd.onecmd(str)

解释参数,就像它是对提示符的响应一样输入的。这可以被覆盖,但通常不需要;有关有用的执行挂钩,请参见 precmd()postcmd() 方法。返回值是一个标志,指示解释器是否应停止解释命令。如果命令 str 有一个 do_*() 方法,则返回该方法的返回值,否则返回 default() 方法的返回值。

Cmd.emptyline()

在响应提示时输入空行时调用的方法。如果未覆盖此方法,它将重复输入的最后一个非空命令。

Cmd.default(line)

当命令前缀无法识别时,在输入行中调用的方法。如果未覆盖此方法,它将打印错误消息并返回。

Cmd.completedefault(text, line, begidx, endidx)

当没有命令特定的 complete_*() 方法可用时,调用此方法来完成输入行。默认情况下,它返回一个空列表。

Cmd.columnize(list, displaywidth=80)

调用此方法将一组字符串列表显示为一组紧凑的列。每列的宽度仅为必要宽度。为了便于阅读,列之间用两个空格分隔。

Cmd.precmd(line)

在解释命令行 line 之前执行的钩子方法,但在生成并发出输入提示之后。此方法在 Cmd 中是一个存根;它的存在是为了被子类覆盖。返回值用作将由 onecmd() 方法执行的命令;precmd() 实现可以重写命令或简单地返回未更改的 line

Cmd.postcmd(stop, line)

命令分派完成后立即执行的挂钩方法。此方法在 Cmd 中是一个存根;它存在是为了被子类覆盖。line 是已执行的命令行,而 stop 是一个标志,它指示在调用 postcmd() 后是否终止执行;这将是 onecmd() 方法的返回值。此方法的返回值将用作与 stop 相对应的内部标志的新值;返回 false 将导致解释继续进行。

Cmd.preloop()

当调用 cmdloop() 时一次执行的挂钩方法。此方法在 Cmd 中是一个存根;它存在是为了被子类覆盖。

Cmd.postloop()

cmdloop() 即将返回时一次执行的挂钩方法。此方法在 Cmd 中是一个存根;它存在是为了被子类覆盖。

Cmd 子类的实例有一些公共实例变量

Cmd.prompt

发出以征求输入的提示。

Cmd.identchars

命令前缀接受的字符字符串。

Cmd.lastcmd

看到的最后一个非空命令前缀。

Cmd.cmdqueue

已排队的输入行列表。当需要新输入时,将在 cmdloop() 中检查 cmdqueue 列表;如果它是非空的,则会按顺序处理其元素,就像在提示符处输入一样。

Cmd.intro

作为介绍或横幅发出的字符串。可以通过向 cmdloop() 方法提供一个参数来覆盖。

Cmd.doc_header

如果帮助输出有已记录命令部分,则发出的标题。

Cmd.misc_header

如果帮助输出有杂项帮助主题部分,则发出的标题(即,有 help_*() 方法而没有相应的 do_*() 方法)。

Cmd.undoc_header

如果帮助输出有未记录命令部分,则发出的标题(即,有 do_*() 方法而没有相应的 help_*() 方法)。

Cmd.ruler

用于在帮助消息标题下绘制分隔线的字符。如果为空,则不绘制标尺线。默认为 '='

Cmd.use_rawinput

一个标志,默认为真。如果为真,则 cmdloop() 使用 input() 显示提示并读取下一个命令;如果为假,则使用 sys.stdout.write()sys.stdin.readline()。(这意味着通过导入 readline,在支持它的系统上,解释器将自动支持 Emacs 类似的行编辑和命令历史记录击键。)

Cmd 示例

cmd 模块主要用于构建自定义 shell,让用户可以交互地使用程序。

本节介绍如何围绕 turtle 模块中的几个命令构建 shell 的一个简单示例。

forward() 等基本 turtle 命令添加到 Cmd 子类,方法名为 do_forward()。将参数转换为数字并分派到 turtle 模块。文档字符串用于 shell 提供的帮助实用程序中。

该示例还包括一个使用 precmd() 方法实现的基本记录和回放功能,该方法负责将输入转换为小写并将命令写入文件。 do_playback() 方法读取文件并将记录的命令添加到 cmdqueue 以立即回放

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

    # ----- basic turtle commands -----
    def do_forward(self, arg):
        'Move the turtle forward by the specified distance:  FORWARD 10'
        forward(*parse(arg))
    def do_right(self, arg):
        'Turn turtle right by given number of degrees:  RIGHT 20'
        right(*parse(arg))
    def do_left(self, arg):
        'Turn turtle left by given number of degrees:  LEFT 90'
        left(*parse(arg))
    def do_goto(self, arg):
        'Move turtle to an absolute position with changing orientation.  GOTO 100 200'
        goto(*parse(arg))
    def do_home(self, arg):
        'Return turtle to the home position:  HOME'
        home()
    def do_circle(self, arg):
        'Draw circle with given radius an options extent and steps:  CIRCLE 50'
        circle(*parse(arg))
    def do_position(self, arg):
        'Print the current turtle position:  POSITION'
        print('Current position is %d %d\n' % position())
    def do_heading(self, arg):
        'Print the current turtle heading in degrees:  HEADING'
        print('Current heading is %d\n' % (heading(),))
    def do_color(self, arg):
        'Set the color:  COLOR BLUE'
        color(arg.lower())
    def do_undo(self, arg):
        'Undo (repeatedly) the last turtle action(s):  UNDO'
    def do_reset(self, arg):
        'Clear the screen and return turtle to center:  RESET'
        reset()
    def do_bye(self, arg):
        'Stop recording, close the turtle window, and exit:  BYE'
        print('Thank you for using Turtle')
        self.close()
        bye()
        return True

    # ----- record and playback -----
    def do_record(self, arg):
        'Save future commands to filename:  RECORD rose.cmd'
        self.file = open(arg, 'w')
    def do_playback(self, arg):
        'Playback commands from a file:  PLAYBACK rose.cmd'
        self.close()
        with open(arg) as f:
            self.cmdqueue.extend(f.read().splitlines())
    def precmd(self, line):
        line = line.lower()
        if self.file and 'playback' not in line:
            print(line, file=self.file)
        return line
    def close(self):
        if self.file:
            self.file.close()
            self.file = None

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()

以下是 turtle shell 的示例会话,显示帮助函数、使用空行重复命令以及简单的记录和回放功能

Welcome to the turtle shell.   Type help or ? to list commands.

(turtle) ?

Documented commands (type help <topic>):
========================================
bye     color    goto     home  playback  record  right
circle  forward  heading  left  position  reset   undo

(turtle) help forward
Move the turtle forward by the specified distance:  FORWARD 10
(turtle) record spiral.cmd
(turtle) position
Current position is 0 0

(turtle) heading
Current heading is 0

(turtle) reset
(turtle) circle 20
(turtle) right 30
(turtle) circle 40
(turtle) right 30
(turtle) circle 60
(turtle) right 30
(turtle) circle 80
(turtle) right 30
(turtle) circle 100
(turtle) right 30
(turtle) circle 120
(turtle) right 30
(turtle) circle 120
(turtle) heading
Current heading is 180

(turtle) forward 100
(turtle)
(turtle) right 90
(turtle) forward 100
(turtle)
(turtle) right 90
(turtle) forward 400
(turtle) right 90
(turtle) forward 500
(turtle) right 90
(turtle) forward 400
(turtle) right 90
(turtle) forward 300
(turtle) playback spiral.cmd
Current position is 0 0

Current heading is 0

Current heading is 180

(turtle) bye
Thank you for using Turtle