cmd — 面向行的命令直譯器支援

原始碼: Lib/cmd.py


Cmd 類為編寫面向行的命令直譯器提供了一個簡單的框架。這些通常對於測試工具、管理工具以及稍後將包裝在更復雜介面中的原型很有用。

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

Cmd 例項或子類例項是一個面向行的直譯器框架。沒有充分的理由例項化 Cmd 本身;相反,它作為您自己定義的直譯器類的超類很有用,以便繼承 Cmd 的方法並封裝操作方法。

可選引數 completekeyreadline 的補全鍵的名稱;預設為 Tab。如果 completekey 不是 Nonereadline 可用,則會自動進行命令補全。

預設值 'tab' 會被特殊處理,以便在每個 readline.backend 上都指 Tab 鍵。具體來說,如果 readline.backendeditline,則 Cmd 將使用 '^I' 而不是 'tab'。請注意,其他值不會以這種方式處理,可能只適用於特定的後端。

可選引數 stdinstdout 指定 Cmd 例項或子類例項將用於輸入和輸出的輸入和輸出檔案物件。如果未指定,則它們將預設為 sys.stdinsys.stdout

如果要使用給定的 stdin,請確保將例項的 use_rawinput 屬性設定為 False,否則將忽略 stdin

在 3.13 版本中變更: completekey='tab' 對於 editline 被替換為 '^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_*() 方法的返回值。

如果啟用了補全,則將自動完成命令,並且透過使用引數 textlinebegidxendidx 呼叫 complete_foo() 來完成命令引數。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

如果幫助輸出具有雜項幫助主題的部分(即,存在沒有相應 do_*() 方法的 help_*() 方法),則要發出的標題。

Cmd.undoc_header

如果幫助輸出具有未記錄命令的部分(即,存在沒有相應 help_*() 方法的 do_*() 方法),則要發出的標題。

Cmd.ruler

用於在幫助訊息標題下繪製分隔線的字元。如果為空,則不繪製標尺線。它預設為 '='

Cmd.use_rawinput

一個標誌,預設為 true。如果為 true,則 cmdloop() 使用 input() 來顯示提示符並讀取下一個命令;如果為 false,則使用 sys.stdout.write()sys.stdin.readline()。(這意味著透過匯入 readline,在支援它的系統上,直譯器將自動支援類似 Emacs 的行編輯和命令歷史按鍵。)

Cmd 示例

cmd 模組主要用於構建自定義 shell,使使用者可以互動地使用程式。

本節提供了一個簡單示例,說明如何圍繞 turtle 模組中的幾個命令構建 shell。

基本的 turtle 命令,例如 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