cmd — Unterstützung für zeilenorientierte Befehlsinterpreter

Quellcode: Lib/cmd.py


Die Klasse Cmd bietet ein einfaches Framework für die Erstellung zeilenorientierter Befehlsinterpreter. Diese sind oft nützlich für Testgerüste, Verwaltungs-Tools und Prototypen, die später in eine anspruchsvollere Schnittstelle eingebettet werden.

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

Eine Instanz oder Unterklasse von Cmd ist ein zeilenorientiertes Interpreter-Framework. Es gibt keinen guten Grund, Cmd selbst zu instanziieren; vielmehr ist es nützlich als Oberklasse einer von Ihnen selbst definierten Interpreter-Klasse, um die Methoden von Cmd zu erben und Aktionsmethoden zu kapseln.

Das optionale Argument completekey ist der readline-Name für eine Vervollständigungstaste; er hat standardmäßig den Wert Tab. Wenn completekey nicht None ist und readline verfügbar ist, erfolgt die Befehlsvervollständigung automatisch.

Der Standardwert 'tab' wird speziell behandelt, sodass er sich auf die Tabulator-Taste auf jedem readline.backend bezieht. Insbesondere wenn readline.backend editline ist, verwendet Cmd stattdessen '^I' anstelle von 'tab'. Beachten Sie, dass andere Werte nicht auf diese Weise behandelt werden und möglicherweise nur mit einem bestimmten Backend funktionieren.

Die optionalen Argumente stdin und stdout geben die Eingabe- und Ausgabedatei-Objekte an, die die Cmd-Instanz oder Unterklasseninstanz für Eingabe und Ausgabe verwendet. Wenn sie nicht angegeben werden, werden sie standardmäßig zu sys.stdin und sys.stdout.

Wenn Sie möchten, dass ein bestimmtes stdin verwendet wird, stellen Sie sicher, dass das Attribut use_rawinput der Instanz auf False gesetzt ist, andernfalls wird stdin ignoriert.

Geändert in Version 3.13: completekey='tab' wird durch '^I' für editline ersetzt.

Cmd-Objekte

Eine Cmd-Instanz hat die folgenden Methoden

Cmd.cmdloop(intro=None)

Gibt wiederholt eine Eingabeaufforderung aus, nimmt Eingaben entgegen, analysiert ein anfängliches Präfix aus den empfangenen Eingaben und leitet sie an Aktionsmethoden weiter, wobei der Rest der Zeile als Argument übergeben wird.

Das optionale Argument ist eine Banner- oder Intro-Zeichenkette, die vor der ersten Eingabeaufforderung ausgegeben wird (dies überschreibt das Klassenattribut intro).

Wenn das Modul readline geladen ist, erbt die Eingabe automatisch eine **bash**-ähnliche Zeilenbearbeitung mit Verlaufsliste (z. B. Strg-P scrollt zurück zum letzten Befehl, Strg-N vorwärts zum nächsten, Strg-F bewegt den Cursor zerstörungsfrei nach rechts, Strg-B bewegt den Cursor zerstörungsfrei nach links usw.).

Ein End-of-File-Signal bei der Eingabe wird als Zeichenkette 'EOF' zurückgegeben.

Eine Interpreterinstanz erkennt einen Befehlsnamen foo genau dann, wenn sie eine Methode do_foo() hat. Als Sonderfall wird eine Zeile, die mit dem Zeichen '?' beginnt, an die Methode do_help() weitergeleitet. Als weiterer Sonderfall wird eine Zeile, die mit dem Zeichen '!' beginnt, an die Methode do_shell() weitergeleitet (falls eine solche Methode definiert ist).

Diese Methode kehrt zurück, wenn die Methode postcmd() einen wahren Wert zurückgibt. Das Argument stop für postcmd() ist der Rückgabewert der entsprechenden do_*()-Methode des Befehls.

Wenn die Vervollständigung aktiviert ist, werden Befehle automatisch vervollständigt, und die Vervollständigung von Befehlsargumenten erfolgt durch Aufruf von complete_foo() mit den Argumenten text, line, begidx und endidx. text ist das Zeichenkettenpräfix, das wir abzugleichen versuchen: Alle zurückgegebenen Übereinstimmungen müssen damit beginnen. line ist die aktuelle Eingabezeile mit entfernten führenden Leerzeichen, begidx und endidx sind der Anfangs- und Endindex des Präfixtexts, die verwendet werden könnten, um unterschiedliche Vervollständigungen bereitzustellen, abhängig von der Position des Arguments.

Cmd.do_help(arg)

Alle Unterklassen von Cmd erben eine vordefinierte Methode do_help(). Diese Methode ruft mit dem Argument 'bar' die entsprechende Methode help_bar() auf und, falls diese nicht vorhanden ist, gibt die Docstring von do_bar() aus, falls verfügbar. Ohne Argument listet do_help() alle verfügbaren Hilfethemen auf (d. h. alle Befehle mit entsprechenden help_*()-Methoden oder Befehle mit Docstrings) und listet auch alle undokumentierten Befehle auf.

Cmd.onecmd(str)

Interpretiert das Argument so, als wäre es als Antwort auf die Eingabeaufforderung eingegeben worden. Dies kann überschrieben werden, sollte aber normalerweise nicht erforderlich sein. Siehe die Methoden precmd() und postcmd() für nützliche Ausführungshooks. Der Rückgabewert ist ein Flag, das angibt, ob die Interpretation von Befehlen durch den Interpreter gestoppt werden soll. Wenn es eine do_*()-Methode für den Befehl str gibt, wird der Rückgabewert dieser Methode zurückgegeben, andernfalls wird der Rückgabewert der Methode default() zurückgegeben.

Cmd.emptyline()

Methode, die aufgerufen wird, wenn eine leere Zeile als Antwort auf die Eingabeaufforderung eingegeben wird. Wenn diese Methode nicht überschrieben wird, wiederholt sie den zuletzt eingegebenen nicht leeren Befehl.

Cmd.default(line)

Methode, die für eine Eingabezeile aufgerufen wird, wenn das Befehlspräfix nicht erkannt wird. Wenn diese Methode nicht überschrieben wird, gibt sie eine Fehlermeldung aus und kehrt zurück.

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

Methode, die aufgerufen wird, um eine Eingabezeile zu vervollständigen, wenn keine Befehl-spezifische complete_*()-Methode verfügbar ist. Standardmäßig gibt sie eine leere Liste zurück.

Cmd.columnize(list, displaywidth=80)

Methode, die aufgerufen wird, um eine Liste von Zeichenketten als kompakte Spalten anzuzeigen. Jede Spalte ist nur so breit wie nötig. Spalten sind zur besseren Lesbarkeit durch zwei Leerzeichen getrennt.

Cmd.precmd(line)

Hook-Methode, die kurz vor der Interpretation der Befehlszeile line aufgerufen wird, aber nachdem die Eingabeaufforderung generiert und ausgegeben wurde. Diese Methode ist ein Stub in Cmd; sie existiert, um von Unterklassen überschrieben zu werden. Der Rückgabewert wird als Befehl verwendet, der von der Methode onecmd() ausgeführt wird; die Implementierung von precmd() kann den Befehl umschreiben oder einfach line unverändert zurückgeben.

Cmd.postcmd(stop, line)

Hook-Methode, die kurz nach Abschluss der Befehlsweiterleitung aufgerufen wird. Diese Methode ist ein Stub in Cmd; sie existiert, um von Unterklassen überschrieben zu werden. line ist die ausgeführte Befehlszeile, und stop ist ein Flag, das angibt, ob die Ausführung nach dem Aufruf von postcmd() beendet wird; dies ist der Rückgabewert der Methode onecmd(). Der Rückgabewert dieser Methode wird als neuer Wert für das interne Flag verwendet, das stop entspricht; die Rückgabe von false bewirkt, dass die Interpretation fortgesetzt wird.

Cmd.preloop()

Hook-Methode, die einmal aufgerufen wird, wenn cmdloop() aufgerufen wird. Diese Methode ist ein Stub in Cmd; sie existiert, um von Unterklassen überschrieben zu werden.

Cmd.postloop()

Hook-Methode, die einmal aufgerufen wird, wenn cmdloop() kurz vor der Rückgabe steht. Diese Methode ist ein Stub in Cmd; sie existiert, um von Unterklassen überschrieben zu werden.

Instanzen von Cmd-Unterklassen haben einige öffentliche Instanzvariablen

Cmd.prompt

Die zur Abfrage von Eingaben ausgegebene Eingabeaufforderung.

Cmd.identchars

Die Zeichenkette von Zeichen, die für das Befehlspräfix akzeptiert werden.

Cmd.lastcmd

Das zuletzt gesehene nicht leere Befehlspräfix.

Cmd.cmdqueue

Eine Liste von eingereihten Eingabezeilen. Die Liste `cmdqueue` wird in cmdloop() überprüft, wenn neue Eingaben benötigt werden; wenn sie nicht leer ist, werden ihre Elemente der Reihe nach verarbeitet, als wären sie an der Eingabeaufforderung eingegeben worden.

Cmd.intro

Eine Zeichenkette, die als Intro oder Banner ausgegeben wird. Kann durch Übergabe eines Arguments an die Methode cmdloop() überschrieben werden.

Cmd.doc_header

Die Kopfzeile, die ausgegeben wird, wenn die Hilfeausgabe einen Abschnitt für dokumentierte Befehle enthält.

Cmd.misc_header

Die Kopfzeile, die ausgegeben wird, wenn die Hilfeausgabe einen Abschnitt für verschiedene Hilfethemen enthält (d. h. es gibt help_*()-Methoden ohne entsprechende do_*()-Methoden).

Cmd.undoc_header

Die Kopfzeile, die ausgegeben wird, wenn die Hilfeausgabe einen Abschnitt für undokumentierte Befehle enthält (d. h. es gibt do_*()-Methoden ohne entsprechende help_*()-Methoden).

Cmd.ruler

Das Zeichen, das zum Zeichnen von Trennlinien unter den Hilfemeldungskopfzeilen verwendet wird. Wenn leer, wird keine Trennlinie gezeichnet. Standardmäßig ist es '='.

Cmd.use_rawinput

Ein Flag, das standardmäßig wahr ist. Wenn wahr, verwendet cmdloop() input(), um eine Eingabeaufforderung anzuzeigen und den nächsten Befehl zu lesen; wenn falsch, werden sys.stdout.write() und sys.stdin.readline() verwendet. (Dies bedeutet, dass durch den Import von readline auf Systemen, die dies unterstützen, der Interpreter automatisch **Emacs**-ähnliche Zeilenbearbeitung und Befehlsverlauf-Tastendrücke unterstützt.)

Cmd-Beispiel

Das Modul cmd ist hauptsächlich nützlich zum Erstellen benutzerdefinierter Shells, die es einem Benutzer ermöglichen, interaktiv mit einem Programm zu arbeiten.

Dieser Abschnitt präsentiert ein einfaches Beispiel, wie eine Shell um einige der Befehle des Moduls turtle aufgebaut werden kann.

Grundlegende Turtle-Befehle wie forward() werden zu einer Cmd-Unterklasse mit einer Methode namens do_forward() hinzugefügt. Das Argument wird in eine Zahl umgewandelt und an das Turtle-Modul weitergeleitet. Die Docstring wird im von der Shell bereitgestellten Hilfeprogramm verwendet.

Das Beispiel enthält auch eine einfache Aufzeichnungs- und Wiedergabefunktion, die mit der Methode precmd() implementiert ist, die für die Umwandlung der Eingabe in Kleinbuchstaben und das Schreiben der Befehle in eine Datei verantwortlich ist. Die Methode do_playback() liest die Datei und fügt die aufgezeichneten Befehle der cmdqueue zur sofortigen Wiedergabe hinzu.

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

Hier ist eine Beispiel-Sitzung mit der Turtle-Shell, die die Hilfefunktionen zeigt, leere Zeilen zur Wiederholung von Befehlen verwendet und die einfache Aufzeichnungs- und Wiedergabefunktion nutzt.

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