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

源代码: Lib/cmd.py


Cmd类为编写面向行的命令解释器提供了一个简单的框架。这些通常对于测试工具,Management 工具和原型很有用,这些工具随后将被包装在一个更复杂的界面中。

    • class * cmd. Cmd(* completekey ='tab' stdin = None stdout = None *)
    • Cmd实例或子类实例是面向行的解释器框架。实例化Cmd本身没有充分的理由;相反,它对于您定义自己的解释器类的超类很有用,以便继承Cmd的方法并封装 action 方法。

可选参数* completekey 是完成密钥的readline名称;它默认为 Tab。如果 completekey *不是Nonereadline可用,则命令自动完成。

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

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

Cmd Objects

Cmd实例具有以下方法:

  • Cmd. cmdloop(* intro = None *)
    • 反复发出提示,接受 Importing,从接收到的 Importing 中解析出一个初始前缀,然后分派给操作方法,并将行的其余部分作为参数传递给它们。

可选参数是在第一个提示之前发出的标题或简介字符串(此值将覆盖intro class 属性)。

如果加载了readline模块,则 Importing 将自动继承 bash 之类的历史列表编辑(例如,Control-P 滚动回到上一个命令,Control-N 向前滚动到下一个命令,Control-F 将光标移动到非破坏性地向右移动,Control-B 则以无破坏性地将光标移动到左侧,依此类推)。

Importing 的文件末尾作为字符串'EOF'传回。

解释器实例只有在具有方法do_foo()的情况下,才能识别命令名称foo。在特殊情况下,以字符'?'开头的行被分派给方法do_help()。作为另一种特殊情况,以字符'!'开头的行被分派给方法do_shell()(如果定义了这样的方法)。

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

如果启用了完成,则将自动完成命令的完成,并且pass使用参数* text line begidx endidx *调用complete_foo()来完成命令 args 的完成。 * text *是我们try匹配的字符串前缀:所有返回的匹配项都必须以它开头。 * line 是当前 Importing 行,其中前导空格已删除, begidx endidx *是前缀文本的开始和结束索引,可根据参数所处的位置来提供不同的补全。

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

  • Cmd. onecmd(* str *)

    • 解释该参数,就好像它是根据提示键入的一样。这可能会被覆盖,但通常不需要这么做;有关有用的执行钩子,请参见precmd()postcmd()方法。返回值是一个标志,指示是否应停止解释程序对命令的解释。如果命令* str *有do_*()方法,则返回该方法的返回值,否则返回default()方法的返回值。
  • Cmd. emptyline ( )

    • 响应提示 Importing 空行时调用的方法。如果不重写此方法,它将重复 Importing 的最后一个非空命令。
  • Cmd. default(* line *)

    • 无法识别命令前缀时在 Importing 行上调用的方法。如果未重写此方法,则它会显示一条错误消息并返回。
  • Cmd. completedefault(* text line begidx endidx *)

    • 在没有特定于命令的complete_*()方法可用时调用此方法来完成 Importing 行。默认情况下,它返回一个空列表。
  • Cmd. precmd(* line *)

    • 在解释命令行* line 之前但在生成并发出 Importing 提示之后执行的 Hook 方法。此方法是Cmd中的存根;它存在被子类覆盖。返回值用作将由onecmd()方法执行的命令; precmd()实现可以重新编写命令或简单地返回 line *不变。
  • Cmd. postcmd(* stop line *)

    • 在命令分派完成后立即执行的 Hook 方法。此方法是Cmd中的存根;它存在被子类覆盖。 * line 是执行的命令行, stop 是指示在调用postcmd()之后是否将终止执行的标志;这将是onecmd()方法的返回值。此方法的返回值将用作与 stop *对应的内部标志的新值;返回 false 将导致解释 continue。
  • Cmd. preloop ( )

    • 调用cmdloop()时,钩子方法执行一次。此方法是Cmd中的存根;它存在被子类覆盖。
  • Cmd. postloop ( )

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

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

  • Cmd. prompt

    • 发出提示以征求 Importing。
  • Cmd. identchars

    • 命令前缀接受的字符字符串。
  • Cmd. lastcmd

    • 看到的最后一个非空命令前缀。
  • Cmd. cmdqueue

    • 排队的 Importing 行列表。需要新 Importing 时,会在cmdloop()中检查 cmdqueue 列表;如果它是非空的,则将按 Sequences 处理其元素,就像在提示符下 Importing 一样。
  • Cmd. intro

    • 要作为简介或横幅发布的字符串。可以pass为cmdloop()方法提供参数来覆盖它。
  • Cmd. doc_header

    • 如果帮助输出中有记录文档的部分,则发出的标题。
  • Cmd. misc_header

    • 如果帮助输出中包含有关其他帮助主题的部分(即,有help_*()个方法而没有相应的do_*()个方法),则会发出的标题。
  • Cmd. undoc_header

    • 如果帮助输出中包含未记录命令的部分,则要发出的标题(即,有do_*()个方法而没有相应的help_*()个方法)。
  • Cmd. ruler

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

    • 一个标志,默认为 true。如果为 true,则cmdloop()使用input()显示提示并阅读下一条命令;如果为 false,则使用sys.stdout.write()sys.stdin.readline()。 (这意味着,pass在支持readline的系统上导入readline,解释器将自动支持 Emacs 之类的行编辑和命令历史击键。)

Cmd Example

cmd模块主要用于构建可让用户以交互方式使用程序的自定义 Shell。

本节提供一个简单的示例,说明如何围绕turtle模块中的一些命令构建 Shell。

基本的turtle 命令(例如forward())pass名为do_forward()的方法添加到Cmd子类中。该参数将转换为数字,然后分派给 turtle 模块。该文档字符串在 Shell 程序提供的帮助 Util 中使用。

该示例还包括使用precmd()方法实现的基本记录和回放Function,该方法负责将 Importing 转换为小写并将命令写入文件。 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()

这是一个示例会话,其中的turtleShell 显示了帮助Function,使用空行重复命令以及简单的记录和回放Function:

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