shlex — Einfache lexikalische Analyse

Quellcode: Lib/shlex.py


Die Klasse shlex erleichtert das Schreiben von lexikalischen Analysatoren für einfache Syntaxen, die der Unix-Shell ähneln. Dies ist oft nützlich für das Schreiben von Minisprachen (z. B. in Konfigurationsdateien für Python-Anwendungen) oder zum Parsen von Anführungszeichen-Strings.

Das Modul shlex definiert die folgenden Funktionen

shlex.split(s, comments=False, posix=True)

Teilt den String s unter Verwendung einer Shell-ähnlichen Syntax. Wenn comments False (Standard) ist, ist die Analyse von Kommentaren im gegebenen String deaktiviert (das Attribut commenters der shlex-Instanz wird auf einen leeren String gesetzt). Diese Funktion arbeitet standardmäßig im POSIX-Modus, verwendet jedoch den Nicht-POSIX-Modus, wenn das Argument posix falsch ist.

Geändert in Version 3.12: Das Übergeben von None für das Argument s löst nun eine Ausnahme aus, anstatt von sys.stdin zu lesen.

shlex.join(split_command)

Verkettet die Token der Liste split_command und gibt einen String zurück. Diese Funktion ist die Umkehrung von split().

>>> from shlex import join
>>> print(join(['echo', '-n', 'Multiple words']))
echo -n 'Multiple words'

Der zurückgegebene Wert ist Shell-escaped, um Injection-Schwachstellen zu vermeiden (siehe quote()).

Hinzugefügt in Version 3.8.

shlex.quote(s)

Gibt eine Shell-escaped Version des Strings s zurück. Der zurückgegebene Wert ist ein String, der sicher als ein einzelnes Token in einer Shell-Befehlszeile verwendet werden kann, für Fälle, in denen Sie keine Liste verwenden können.

Warnung

Das Modul shlex ist nur für Unix-Shells konzipiert.

Die Funktion quote() ist nicht garantiert korrekt für nicht-POSIX-konforme Shells oder Shells anderer Betriebssysteme wie Windows. Die Ausführung von mit diesem Modul gequoteten Befehlen auf solchen Shells kann zu Command-Injection-Schwachstellen führen.

Erwägen Sie die Verwendung von Funktionen, die Befehlsargumente als Listen übergeben, wie z. B. subprocess.run() mit shell=False.

Dieses Idiom wäre unsicher

>>> filename = 'somefile; rm -rf ~'
>>> command = 'ls -l {}'.format(filename)
>>> print(command)  # executed by a shell: boom!
ls -l somefile; rm -rf ~

quote() schließt die Sicherheitslücke

>>> from shlex import quote
>>> command = 'ls -l {}'.format(quote(filename))
>>> print(command)
ls -l 'somefile; rm -rf ~'
>>> remote_command = 'ssh home {}'.format(quote(command))
>>> print(remote_command)
ssh home 'ls -l '"'"'somefile; rm -rf ~'"'"''

Die Quoting ist kompatibel mit UNIX-Shells und mit split()

>>> from shlex import split
>>> remote_command = split(remote_command)
>>> remote_command
['ssh', 'home', "ls -l 'somefile; rm -rf ~'"]
>>> command = split(remote_command[-1])
>>> command
['ls', '-l', 'somefile; rm -rf ~']

Hinzugefügt in Version 3.3.

Das Modul shlex definiert die folgende Klasse

class shlex.shlex(instream=None, infile=None, posix=False, punctuation_chars=False)

Eine Instanz von shlex oder eine Instanz einer Unterklasse ist ein lexikalisches Analyseobjekt. Das Initialisierungsargument gibt, falls vorhanden, an, woher Zeichen gelesen werden sollen. Es muss ein datei-/stream-ähnliches Objekt mit Methoden read() und readline() oder ein String sein. Wenn kein Argument angegeben wird, werden Eingaben von sys.stdin gelesen. Das zweite optionale Argument ist ein Dateiname-String, der den Anfangswert des Attributs infile setzt. Wenn das Argument instream weggelassen wird oder gleich sys.stdin ist, ist dieses zweite Argument standardmäßig „stdin“. Das Argument posix definiert den Betriebsmodus: Wenn posix nicht wahr ist (Standard), arbeitet die shlex-Instanz im Kompatibilitätsmodus. Im POSIX-Modus versucht shlex, so nah wie möglich an den POSIX-Shell-Parsing-Regeln zu sein. Das Argument punctuation_chars bietet eine Möglichkeit, das Verhalten noch näher an die Art und Weise anzupassen, wie echte Shells parsen. Dies kann eine Reihe von Werten annehmen: Der Standardwert False behält das Verhalten bei, das unter Python 3.5 und früheren Versionen zu sehen war. Wenn es auf True gesetzt wird, ändert sich die Analyse der Zeichen ();<>|&: Jeder Lauf dieser Zeichen (als Satzzeichen betrachtet) wird als einzelnes Token zurückgegeben. Wenn es auf einen nicht leeren String von Zeichen gesetzt wird, werden diese Zeichen als Satzzeichen verwendet. Zeichen im Attribut wordchars, die in punctuation_chars vorkommen, werden aus wordchars entfernt. Siehe Verbesserte Kompatibilität mit Shells für weitere Informationen. punctuation_chars kann nur bei der Erstellung einer shlex-Instanz gesetzt und später nicht mehr geändert werden.

Geändert in Version 3.6: Der Parameter punctuation_chars wurde hinzugefügt.

Siehe auch

Modul configparser

Parser für Konfigurationsdateien ähnlich den Windows .ini-Dateien.

shlex-Objekte

Eine Instanz von shlex hat die folgenden Methoden

shlex.get_token()

Gibt ein Token zurück. Wenn Tokens mit push_token() gestapelt wurden, wird ein Token vom Stapel genommen. Andernfalls wird eines aus dem Eingabestream gelesen. Wenn das Lesen auf ein sofortiges Dateiende stößt, wird eof zurückgegeben (der leere String ('') im Nicht-POSIX-Modus und None im POSIX-Modus).

shlex.push_token(str)

Legt das Argument auf den Token-Stapel.

shlex.read_token()

Liest ein rohes Token. Ignoriert den Rückschiebestapel und interpretiert keine Quellenanfragen. (Dies ist normalerweise kein nützlicher Einstiegspunkt und wird hier nur der Vollständigkeit halber dokumentiert.)

shlex.sourcehook(filename)

Wenn shlex eine Quellenanfrage erkennt (siehe source unten), wird diese Methode mit dem folgenden Token als Argument aufgerufen und soll ein Tupel zurückgeben, das aus einem Dateinamen und einem geöffneten dateiähnlichen Objekt besteht.

Normalerweise entfernt diese Methode zuerst alle Anführungszeichen vom Argument. Wenn das Ergebnis ein absoluter Pfadname ist, oder keine vorherige Quellenanfrage in Kraft war, oder die vorherige Quelle ein Stream war (wie z. B. sys.stdin), bleibt das Ergebnis unverändert. Andernfalls, wenn das Ergebnis ein relativer Pfadname ist, wird der Verzeichnisteil des Namens der Datei, die ihm unmittelbar auf dem Stapel der Quellcode-Einbindung folgt, vorangestellt (dieses Verhalten ähnelt der Art und Weise, wie der C-Präprozessor #include "file.h" behandelt).

Das Ergebnis der Manipulationen wird als Dateiname behandelt und als erste Komponente des Tupels zurückgegeben, wobei open() darauf aufgerufen wird, um die zweite Komponente zu liefern. (Hinweis: dies ist die umgekehrte Reihenfolge der Argumente bei der Instanzinitialisierung!)

Dieser Hook wird bereitgestellt, damit Sie ihn zur Implementierung von Verzeichnissuchpfaden, zum Hinzufügen von Dateierweiterungen und anderen Namespace-Hacks verwenden können. Es gibt keinen entsprechenden ‚close‘-Hook, aber eine shlex-Instanz ruft die Methode close() des gelesenen Eingabestroms auf, wenn er EOF zurückgibt.

Für eine explizitere Steuerung der Quellcode-Einbindung verwenden Sie die Methoden push_source() und pop_source().

shlex.push_source(newstream, newfile=None)

Fügt einen Eingabequellen-Stream auf den Eingabestapel auf. Wenn das Dateiname-Argument angegeben wird, ist es später für die Verwendung in Fehlermeldungen verfügbar. Dies ist dieselbe Methode, die intern von der Methode sourcehook() verwendet wird.

shlex.pop_source()

Nimmt die zuletzt hinzugefügte Eingabequelle vom Eingabestapel. Dies ist dieselbe Methode, die intern verwendet wird, wenn der Lexer das EOF auf einem gestapelten Eingabestrom erreicht.

shlex.error_leader(infile=None, lineno=None)

Diese Methode generiert eine Fehlermeldungs-Überschrift im Format eines Unix C-Compiler-Fehleretiketts; das Format ist '"%s", line %d: ', wobei %s durch den Namen der aktuellen Quelldatei und %d durch die aktuelle Eingabezeilennummer ersetzt wird (die optionalen Argumente können verwendet werden, um diese zu überschreiben).

Diese Annehmlichkeit wird bereitgestellt, um Benutzer von shlex zu ermutigen, Fehlermeldungen im standardmäßigen, parsierbaren Format zu generieren, das von Emacs und anderen Unix-Tools verstanden wird.

Instanzen von Unterklassen von shlex haben einige öffentliche Instanzvariablen, die entweder die lexikalische Analyse steuern oder zum Debuggen verwendet werden können

shlex.commenters

Der String von Zeichen, die als Kommentar-Beginn erkannt werden. Alle Zeichen vom Kommentar-Beginn bis zum Zeilenende werden ignoriert. Enthält standardmäßig nur '#'.

shlex.wordchars

Der String von Zeichen, die sich zu mehrzeichenigen Tokens ansammeln. Standardmäßig sind dies alle ASCII-Alphanumerika und Unterstriche. Im POSIX-Modus sind auch die akzentuierten Zeichen des Latin-1-Zeichensatzes enthalten. Wenn punctuation_chars nicht leer ist, werden die Zeichen ~-./*?=, die in Dateinamen-Spezifikationen und Kommandozeilenparametern vorkommen können, ebenfalls in dieses Attribut aufgenommen, und alle Zeichen, die in punctuation_chars vorkommen, werden aus wordchars entfernt, wenn sie dort vorhanden sind. Wenn whitespace_split auf True gesetzt ist, hat dies keine Auswirkung.

shlex.whitespace

Zeichen, die als Leerzeichen betrachtet und übersprungen werden. Leerzeichen begrenzen Tokens. Standardmäßig sind dies Leerzeichen, Tabulator, Zeilenvorschub und Wagenrücklauf.

shlex.escape

Zeichen, die als Escape-Zeichen betrachtet werden. Dies wird nur im POSIX-Modus verwendet und enthält standardmäßig nur '\'.

shlex.quotes

Zeichen, die als Anführungszeichen betrachtet werden. Das Token sammelt sich an, bis dasselbe Anführungszeichen erneut angetroffen wird (somit schützen verschiedene Anführungszeichen-Typen einander wie in der Shell). Standardmäßig sind dies ASCII-Einzel- und Doppelanführungszeichen.

shlex.escapedquotes

Zeichen in quotes, die Escape-Zeichen interpretieren, die in escape definiert sind. Dies wird nur im POSIX-Modus verwendet und enthält standardmäßig nur '"'.

shlex.whitespace_split

Wenn True, werden Tokens nur durch Leerzeichen getrennt. Dies ist nützlich, z. B. zum Parsen von Kommandozeilen mit shlex, um Tokens ähnlich wie Shell-Argumente zu erhalten. Bei Verwendung in Kombination mit punctuation_chars werden Tokens zusätzlich zu diesen Zeichen durch Leerzeichen getrennt.

Geändert in Version 3.8: Das Attribut punctuation_chars wurde mit dem Attribut whitespace_split kompatibel gemacht.

shlex.infile

Der Name der aktuellen Eingabedatei, wie er bei der Instanziierung der Klasse festgelegt oder durch spätere Quellenanfragen gestapelt wurde. Es kann nützlich sein, dies bei der Erstellung von Fehlermeldungen zu untersuchen.

shlex.instream

Der Eingabestream, von dem diese shlex-Instanz Zeichen liest.

shlex.source

Dieses Attribut ist standardmäßig None. Wenn Sie ihm einen String zuweisen, wird dieser String als eine lexikalische Einbindungsanfrage erkannt, ähnlich dem Schlüsselwort source in verschiedenen Shells. Das bedeutet, dass das unmittelbar folgende Token als Dateiname geöffnet wird und von diesem Stream bis zum EOF gelesen wird, woraufhin die Methode close() dieses Streams aufgerufen wird und die Eingabequelle wieder der ursprüngliche Eingabestream wird. Quellenanfragen können beliebig tief gestapelt werden.

shlex.debug

Wenn dieses Attribut numerisch und 1 oder größer ist, gibt eine shlex-Instanz detaillierte Fortschrittsausgaben über ihr Verhalten aus. Wenn Sie dies verwenden müssen, können Sie den Modulquellcode lesen, um die Details zu erfahren.

shlex.lineno

Quellzeilennummer (Anzahl der bisher gesehenen Zeilenumbrüche plus eins).

shlex.token

Der Token-Puffer. Es kann nützlich sein, dies beim Abfangen von Ausnahmen zu untersuchen.

shlex.eof

Token, das zur Bestimmung des Dateiendes verwendet wird. Dies wird auf den leeren String ('') im Nicht-POSIX-Modus und auf None im POSIX-Modus gesetzt.

shlex.punctuation_chars

Eine schreibgeschützte Eigenschaft. Zeichen, die als Satzzeichen betrachtet werden. Läufe von Satzzeichen werden als einzelnes Token zurückgegeben. Beachten Sie jedoch, dass keine semantische Gültigkeitsprüfung durchgeführt wird: Zum Beispiel kann „>>>“ als Token zurückgegeben werden, auch wenn es von Shells möglicherweise nicht als solches erkannt wird.

Hinzugefügt in Version 3.6.

Parsing-Regeln

Im Nicht-POSIX-Modus versucht shlex, die folgenden Regeln zu befolgen.

  • Anführungszeichen werden innerhalb von Wörtern nicht erkannt (Do"Not"Separate wird als einzelnes Wort Do"Not"Separate geparst);

  • Escape-Zeichen werden nicht erkannt;

  • Das Umschließen von Zeichen in Anführungszeichen bewahrt den literalen Wert aller Zeichen innerhalb der Anführungszeichen;

  • Schließende Anführungszeichen trennen Wörter ("Do"Separate wird als "Do" und Separate geparst);

  • Wenn whitespace_split False ist, wird jedes Zeichen, das nicht als Wortzeichen, Leerzeichen oder Anführungszeichen deklariert ist, als einzelnes Zeichen-Token zurückgegeben. Wenn es True ist, trennt shlex Wörter nur durch Leerzeichen;

  • EOF wird durch einen leeren String ('') signalisiert;

  • Es ist nicht möglich, leere Strings zu parsen, auch wenn sie zitiert sind.

Im POSIX-Modus versucht shlex, die folgenden Parsing-Regeln zu befolgen.

  • Anführungszeichen werden entfernt und trennen keine Wörter ("Do"Not"Separate" wird als einzelnes Wort DoNotSeparate geparst);

  • Nicht zitierte Escape-Zeichen (z. B. '\') bewahren den literalen Wert des nächsten Zeichens, das folgt;

  • Das Umschließen von Zeichen in Anführungszeichen, die nicht Teil von escapedquotes sind (z. B. "'"), bewahrt den literalen Wert aller Zeichen innerhalb der Anführungszeichen;

  • Das Umschließen von Zeichen in Anführungszeichen, die Teil von escapedquotes sind (z. B. '"'), bewahrt den literalen Wert aller Zeichen innerhalb der Anführungszeichen, mit Ausnahme der in escape genannten Zeichen. Die Escape-Zeichen behalten ihre spezielle Bedeutung nur, wenn sie vom verwendeten Anführungszeichen oder dem Escape-Zeichen selbst gefolgt werden. Andernfalls wird das Escape-Zeichen als normales Zeichen behandelt.

  • EOF wird mit einem None-Wert signalisiert;

  • Anführungszeichen um leere Strings ('') sind erlaubt.

Verbesserte Kompatibilität mit Shells

Hinzugefügt in Version 3.6.

Die Klasse shlex bietet Kompatibilität mit dem Parsen, das von gängigen Unix-Shells wie bash, dash und sh durchgeführt wird. Um diese Kompatibilität zu nutzen, geben Sie das Argument punctuation_chars im Konstruktor an. Dieses ist standardmäßig auf False gesetzt, was das Verhalten vor 3.6 beibehält. Wenn es jedoch auf True gesetzt wird, ändert sich das Parsen der Zeichen ();<>|&: Jede Sequenz dieser Zeichen wird als ein einzelnes Token zurückgegeben. Obwohl dies noch kein vollständiger Parser für Shells ist (was angesichts der Vielfalt an Shells den Rahmen der Standardbibliothek sprengen würde), ermöglicht es Ihnen, Befehlszeilen einfacher zu verarbeiten als bisher. Zur Veranschaulichung sehen Sie den Unterschied im folgenden Ausschnitt

>>> import shlex
>>> text = "a && b; c && d || e; f >'abc'; (def \"ghi\")"
>>> s = shlex.shlex(text, posix=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b;', 'c', '&&', 'd', '||', 'e;', 'f', '>abc;', '(def', 'ghi)']
>>> s = shlex.shlex(text, posix=True, punctuation_chars=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b', ';', 'c', '&&', 'd', '||', 'e', ';', 'f', '>', 'abc', ';',
'(', 'def', 'ghi', ')']

Natürlich werden auch Tokens zurückgegeben, die für Shells nicht gültig sind, und Sie müssen Ihre eigenen Fehlerprüfungen für die zurückgegebenen Tokens implementieren.

Anstatt True als Wert für den Parameter punctuation_chars zu übergeben, können Sie einen String mit bestimmten Zeichen übergeben, der bestimmt, welche Zeichen als Satzzeichen gelten. Zum Beispiel

>>> import shlex
>>> s = shlex.shlex("a && b || c", punctuation_chars="|")
>>> list(s)
['a', '&', '&', 'b', '||', 'c']

Hinweis

Wenn punctuation_chars angegeben ist, wird das Attribut wordchars mit den Zeichen ~-./*?= erweitert. Dies liegt daran, dass diese Zeichen in Dateinamen (einschließlich Wildcards) und Kommandozeilenargumenten (z. B. --color=auto) vorkommen können. Daher

>>> import shlex
>>> s = shlex.shlex('~/a && b-c --color=auto || d *.py?',
...                 punctuation_chars=True)
>>> list(s)
['~/a', '&&', 'b-c', '--color=auto', '||', 'd', '*.py?']

Um der Shell jedoch so nahe wie möglich zu kommen, wird empfohlen, immer posix und whitespace_split zu verwenden, wenn punctuation_chars verwendet wird, was wordchars vollständig negiert.

Für die beste Wirkung sollte punctuation_chars zusammen mit posix=True gesetzt werden. (Beachten Sie, dass posix=False der Standard für shlex ist.)