cmd
— 支持面向行的命令解释器¶
源代码:Lib/cmd.py
Cmd
类提供了一个简单的框架,用于编写面向行的命令解释器。这对于测试工具、管理工具以及日后会被包装在更复杂界面中的原型程序通常会很有用。
- class cmd.Cmd(completekey='tab', stdin=None, stdout=None)¶
Cmd
实例或子类的实例是一个面向行的解释器框架。没有很好的理由直接实例化Cmd
;相反地,将它作为你自己定义的解释器类的超类会更有用,这样可以继承Cmd
的方法并封装操作方法。可选参数 completekey 是一个用于补全的键的
readline
名称;它默认为 Tab。如果 completekey 不为None
并且readline
可用,命令补全将自动完成。默认值
'tab'
会被特殊处理,以便它在每个readline.backend
上都指向 Tab 键。具体来说,如果readline.backend
是editline
,Cmd
将会使用'^I'
而不是'tab'
。请注意,其他值不会被这样处理,可能只适用于特定的后端。可选参数 stdin 和 stdout 指定 Cmd 实例或其子类的实例将用于输入和输出的文件对象。如果未指定,它们将默认为
sys.stdin
和sys.stdout
。如果你希望使用给定的 stdin,请确保将实例的
use_rawinput
属性设置为False
,否则 stdin 将被忽略。在 3.13 版更改: 当使用
editline
时,completekey='tab'
会被'^I'
替代。
Cmd 对象¶
一个 Cmd
实例有以下方法
- Cmd.cmdloop(intro=None)¶
重复发出提示,接受输入,从接收到的输入中解析出初始前缀,并将其分派给相应的动作方法,将该行的其余部分作为参数传递给它们。
可选参数是在第一个提示符之前要发出的横幅或介绍字符串(这会重写
intro
类属性)。如果
readline
模块已加载,输入将自动继承类似 bash 的历史列表编辑功能(例如,Control-P 滚动到上一条命令,Control-N 滚动到下一条,Control-F 非破坏性地向右移动光标,Control-B 非破坏性地向左移动光标,等等)。输入时的文件结束符(end-of-file)会作为字符串
'EOF'
返回。一个解释器实例将识别一个命令名
foo
当且仅当它有一个方法do_foo()
。作为一种特殊情况,以字符'?'
开头的行将被分派给方法do_help()
。作为另一种特殊情况,以字符'!'
开头的行将被分派给方法do_shell()
(如果定义了该方法)。当
postcmd()
方法返回一个真值时,此方法将返回。postcmd()
的 stop 参数是命令对应的do_*()
方法的返回值。如果启用了补全,命令的补全将自动完成,而命令参数的补全通过调用
complete_foo()
并附带参数 text, line, begidx 和 endidx 来完成。text 是我们试图匹配的字符串前缀:所有返回的匹配项都必须以它开头。line 是当前输入行,去除了前导空格。begidx 和 endidx 是前缀文本的开始和结束索引,可以根据参数所在的位置提供不同的补全。
- 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
子类的实例有一些公共实例变量
- Cmd.prompt¶
为请求输入而发出的提示符。
- Cmd.identchars¶
可被接受为命令前缀的字符串。
- Cmd.lastcmd¶
所见的最后一个非空命令前缀。
- Cmd.doc_header¶
如果帮助输出有针对已文档化命令的部分,则发出此标题。
- Cmd.misc_header¶
如果帮助输出有针对其他帮助主题的部分(即,存在没有相应
do_*()
方法的help_*()
方法),则发出此标题。
- Cmd.undoc_header¶
如果帮助输出有针对未文档化命令的部分(即,存在没有相应
help_*()
方法的do_*()
方法),则发出此标题。
- Cmd.ruler¶
用于在帮助信息标题下绘制分隔线的字符。如果为空,则不绘制标尺线。它默认为
'='
。
- Cmd.use_rawinput¶
一个标志,默认为真。如果为真,
cmdloop()
使用input()
来显示提示并读取下一个命令;如果为假,则使用sys.stdout.write()
和sys.stdin.readline()
。(这意味着通过导入readline
,在支持它的系统上,解释器将自动支持类似 Emacs 的行编辑和命令历史按键。)
Cmd 示例¶
cmd
模块主要用于构建自定义的 shell,让用户可以与程序进行交互式工作。
本节展示了一个简单的示例,说明如何围绕 turtle
模块中的几个命令构建一个 shell。
像 forward()
这样的基本海龟命令被添加到一个 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