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

源代码: Lib/cmd.py


这个 Cmd 类为编写面向行的命令解释程序提供了一个简单的框架。这些通常对测试工具、管理工具和原型很有用,这些工具稍后将封装在更复杂的接口中。

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

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

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

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

如果你想要一个给定的 *stdin*要使用,请确保设置实例的 use_rawinput 属性到 False ,否则 *stdin*将被忽略。

CMD对象

A 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() 方法返回一个真值。这个 stop 参数 postcmd() 命令的返回值是否与 do_*() 方法。

如果启用了完成,则将自动完成命令,并通过调用 complete_foo() 带着参数 textline贝吉德恩迪克斯 . text 是我们试图匹配的字符串前缀:所有返回的匹配项都必须以它开头。 line 删除了前导空格的当前输入行, 贝吉德恩迪克斯 是前缀文本的开始和结束索引,根据参数所在的位置,可以使用这些索引来提供不同的结束。

的所有子类 Cmd 继承预定义的 do_help() . 此方法,用参数调用 'bar' ,调用相应的方法 help_bar() 如果不存在,则打印 do_bar() ,如果有。没有参数, do_help() 列出所有可用的帮助主题(即,具有相应的 help_*() 方法或具有docstring的命令),还列出任何未记录的命令。

Cmd.onecmd(str)

将参数解释为响应提示而键入的参数。这可能会被覆盖,但通常不需要;请参见 precmd()postcmd() 用于执行挂钩的方法。返回值是一个标志,指示解释器是否应停止对命令的解释。如果有 do_*() 命令的方法 str ,则返回该方法的返回值,否则返回 default() 方法已返回。

Cmd.emptyline()

当输入空行以响应提示时调用的方法。如果不重写此方法,它将重复输入的最后一个非空命令。

Cmd.default(line)

无法识别命令前缀时在输入行上调用的方法。如果不重写此方法,它将打印一条错误消息并返回。

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

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

Cmd.precmd(line)

在命令行之前执行的hook方法 line 解释,但在生成和发出输入提示后。此方法是一个存根 Cmd ;它的存在将被子类重写。返回值用作将由 onecmd() 方法; precmd() 实现可以重新编写命令或简单地返回 line 不变。

Cmd.postcmd(stop, line)

在命令调度完成后执行的hook方法。此方法是一个存根 Cmd ;它的存在将被子类重写。 line 是执行的命令行,并且 stop 是一个标志,指示在调用之后是否将终止执行 postcmd() ;这将是 onecmd() 方法。此方法的返回值将用作对应于 stop ;返回false将导致解释继续进行。

Cmd.preloop()

钩子方法在以下情况下执行一次 cmdloop() 被称为。此方法是一个存根 Cmd ;它的存在将被子类重写。

Cmd.postloop()

钩子方法在以下情况下执行一次 cmdloop() 就要回来了。此方法是一个存根 Cmd ;它的存在将被子类重写。

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

Cmd.prompt

发出请求输入的提示。

Cmd.identchars

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

Cmd.lastcmd

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

Cmd.cmdqueue

排队输入行的列表。已签入CmdQueue列表 cmdloop() 当需要新的输入时;如果它不是空的,它的元素将按顺序处理,就像在提示下输入一样。

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 模块主要用于构建允许用户交互处理程序的自定义shell。

本节提供了一个简单的示例,说明如何围绕 turtle 模块。

基本的turtle命令,如 forward() 被添加到 Cmd 方法名为的子类 do_forward() . 参数转换为数字并发送到Turtle模块。docstring在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