Befehlszeilenargumente in Python

Über uns

Da Python eine sehr beliebte Programmiersprache ist und die meisten Betriebssysteme sowie viele Bibliotheken unterstützt, die die Verarbeitung von Befehlszeilenargumenten vereinfachen, wird es häufig zum Erstellen von Befehlszeilentools für viele Zwecke verwendet. Diese Tools können von einfachen CLI-Apps bis hin zu komplexeren Apps wie AWS reichen. awscli Werkzeug.

Komplexe Tools wie dieses werden typischerweise vom Benutzer über gesteuert Kommandozeilenargumente, wodurch der Benutzer bestimmte Befehle verwenden, Optionen festlegen und mehr verwenden kann. Diese Optionen könnten das Tool beispielsweise anweisen, zusätzliche Informationen auszugeben, Daten aus einer bestimmten Quelle zu lesen oder die Ausgabe an einen bestimmten Ort zu senden.

Im Allgemeinen werden Argumente je nach Betriebssystem unterschiedlich an CLI-Tools übergeben:

  • Unix-ähnlich: - gefolgt von einem Buchstaben, wie -h, oder -- gefolgt von einem Wort, wie --help
  • Windows: / gefolgt von einem Buchstaben oder einem Wort /help

Diese unterschiedlichen Ansätze sind historisch bedingt. Viele Programme auf Unix-ähnlichen Systemen unterstützen sowohl die einfache als auch die doppelte Bindestrich-Notation. Die Schreibweise mit einem einzelnen Bindestrich wird meist bei Einzelbuchstabenoptionen verwendet, während doppelte Bindestriche eine besser lesbare Optionsliste darstellen, was besonders für komplexe Optionen nützlich ist, die expliziter sein müssen.

Note: In diesem Artikel konzentrieren wir uns ausschließlich auf das Unix-ähnliche Format von - und --.

Bedenken Sie, dass sowohl der Name als auch die Bedeutung eines Arguments spezifisch für ein Programm sind – es gibt keine allgemeine Definition, außer ein paar gängigen Konventionen wie --help Weitere Informationen zur Verwendung des Tools finden Sie hier. Als Entwickler eines Python-Skripts entscheiden Sie, welche Argumente Sie dem Aufrufer bereitstellen und was diese tun. Dies erfordert eine ordnungsgemäße Bewertung.

Je länger Ihre Liste verfügbarer Argumente wird, desto komplexer wird Ihr Code bei dem Versuch, diese genau zu analysieren. Glücklicherweise gibt es in Python eine Reihe von Bibliotheken, die Ihnen dabei helfen. Wir werden einige der gängigsten Lösungen behandeln, die von „Do-it-yourself“ bis hin zu reichen sys.argv, zum „Done-for-you“-Ansatz mit argparse.

Umgang mit Befehlszeilenargumenten mit Python

Python 3+ und das umliegende Ökosystem unterstützen eine Reihe unterschiedlicher Möglichkeiten zur Handhabung von Befehlszeilenargumenten. Es gibt viele Bibliotheken, die das Parsen von Befehlszeilenargumenten erleichtern.

Die integrierte Möglichkeit besteht darin, die zu verwenden sys Modul. In Bezug auf Namen und Verwendung bezieht es sich direkt auf die C-Bibliothek (libc).

Der zweite Weg ist der getopt Modul, das sowohl kurze als auch lange Optionen verarbeitet, einschließlich der Auswertung der Parameterwerte.

Das argparse-Modul, die sich aus dem optparse Modul (verfügbar bis Python 2.7).

Das docopt Modul, das ist verfügbar auf GitHubermöglicht auch die gleiche Funktionalität.

Vor kurzem hat die absl Auch die Bibliothek als Mittel zum Ersatz hat an Bedeutung gewonnen optparse und getopt().

Jede dieser Möglichkeiten hat ihre Vor- und Nachteile, daher lohnt es sich, jede einzelne davon zu prüfen, um herauszufinden, welche Ihren Anforderungen am besten entspricht.

Das sys-Modul

Dies ist ein Basismodul, das seit den Anfängen mit Python ausgeliefert wurde. Es verfolgt einen sehr ähnlichen Ansatz wie die Verwendung der C-Bibliothek argc/argv um auf die Argumente zuzugreifen. Der sys-Modul implementiert die Befehlszeilenargumente in einer einfachen Listenstruktur mit dem Namen sys.argv.

Jedes Listenelement stellt ein einzelnes Argument dar. Das erste Element in der Liste, sys.argv[0], ist der Name des Python-Skripts. Die restlichen Listenelemente, sys.argv[1] zu sys.argv[n], sind die Befehlszeilenargumente 2 bis n.

Als Trennzeichen zwischen den Argumenten wird ein Leerzeichen verwendet. Argumentwerte, die ein Leerzeichen enthalten, müssen in Anführungszeichen gesetzt werden, damit sie ordnungsgemäß analysiert werden können sys.

Das Äquivalent von argc ist nur die Anzahl der Elemente in der Liste. Um diesen Wert zu erhalten, verwenden Sie Python len() Operator. Wir werden dies später in einem Codebeispiel zeigen.

Drucken des ersten CLI-Arguments

In diesem ersten Beispiel bestimmt unser Skript die Art und Weise, wie es aufgerufen wurde. Diese Informationen werden im ersten Befehlszeilenargument gespeichert und mit 0 indiziert. Der folgende Code zeigt, wie Sie den Namen Ihres Python-Skripts erhalten:

import sys

print("The script has the name %s" % (sys.argv[0])

Speichern Sie diesen Code in einer Datei mit dem Namen arguments-program-name.py, und rufen Sie es dann wie unten gezeigt auf. Die Ausgabe sieht wie folgt aus und enthält den Dateinamen einschließlich des vollständigen Pfads:

$ python arguments-program-name.py
The script has the name arguments-program-name.py
$ python /home/user/arguments-program-name.py
The script has the name /home/user/arguments-program-name.py

Wie Sie dem zweiten Aufruf oben entnehmen können, erhalten wir nicht nur den Namen der Python-Datei, sondern auch den vollständigen Pfad, über den sie aufgerufen wurde.

Zählen der Anzahl der Argumente

In diesem zweiten Beispiel zählen wir einfach die Anzahl der Befehlszeilenargumente mithilfe der integrierten Funktion len() Methode. sys.argv ist die Liste, die wir untersuchen müssen. Im folgenden Code ermitteln wir die Anzahl der Argumente und subtrahieren dann 1, da eines dieser Argumente (d. h. das erste) immer als Name der Datei festgelegt ist, was für uns nicht immer nützlich ist. Somit beträgt die tatsächliche Anzahl der vom Benutzer übergebenen Argumente len(sys.argv) - 1:

import sys


arguments = len(sys.argv) - 1
print ("The script is called with %i arguments" % (arguments))

Speichern Sie diese Datei und nennen Sie sie arguments-count.py. Nachfolgend finden Sie einige Beispiele für den Aufruf dieses Skripts. Dies umfasst drei verschiedene Szenarien:

  • Ein Aufruf ohne weitere Kommandozeilenargumente
  • Ein Anruf mit zwei Argumenten
  • Ein Aufruf mit zwei Argumenten, wobei das zweite eine Zeichenfolge in Anführungszeichen ist, die ein Leerzeichen enthält
$ python arguments-count.py
The script is called with 0 arguments
$ python arguments-count.py --help me
The script is called with 2 arguments
$ python arguments-count.py --option "long string"
The script is called with 2 arguments
Durch Argumente iterieren

Unser drittes Beispiel gibt jedes einzelne an das Python-Skript gesendete Argument aus, mit Ausnahme des Programmnamens selbst. Daher durchlaufen wir die Befehlszeilenargumente beginnend mit dem zweite Listenelement. Denken Sie daran, dass dies Index 1 ist, da Listen in Python auf 0 basieren:

import sys


arguments = len(sys.argv) - 1


position = 1
while (arguments >= position):
    print ("Parameter %i: %s" % (position, sys.argv[position]))
    position = position + 1

Nachfolgend rufen wir unseren Code auf, der in der Datei arguments-output.py gespeichert wurde. Wie in unserem vorherigen Beispiel veranschaulicht die Ausgabe drei verschiedene Aufrufe:

  • Ein Anruf ohne Argumente
  • Ein Anruf mit zwei Argumenten
  • Ein Aufruf mit zwei Argumenten, wobei das zweite Argument eine Zeichenfolge in Anführungszeichen ist, die ein Leerzeichen enthält
$ python arguments-output.py
$ python arguments-output.py --help me
Parameter 1: --help
Parameter 2: me
$ python arguments-output.py --option "long string"
Parameter 1: --option
Parameter 2: long string

Denken Sie daran, dass es bei der Darstellung des Beispiels für eine Zeichenfolge in Anführungszeichen darum geht, dass Parameter normalerweise durch ein Leerzeichen getrennt werden. es sei denn sie sind von Anführungszeichen umgeben.

Abseilfahnen (absl)

Die Flags-Bibliothek von Abseil soll Befehlszeilenargumente mit verteilten Befehlszeilenargumenten in die Produktion bringen. Wenn ein Modul Befehlszeilenflags verwendet und in ein anderes Modul importiert wird – das andere Modul importiert auch die Flagsund kann diese verarbeiten, indem er sie an das importierte Modul weiterleitet.

Dadurch werden komplexe Befehlszeilenargumente, die von Modulen gemeinsam genutzt werden, einfacher und weniger ausführlich.

Darüber hinaus können Sie in der Bibliothek die Standardwerte, Beschreibungen und Datentypen der Argumente definieren, sodass keine zusätzlichen Prüfungen und Konvertierungen erforderlich sind.

from absl import flags
import sys


flags.DEFINE_string('name', 'User', 'The name of the user.')


FLAGS = flags.FLAGS
FLAGS(sys.argv)

print(f"Hello {FLAGS.name}!")

Die unterstützten Datentypen sind:

  • DEFINE_integer()
  • DEFINE_string()
  • DEFINE_bool()
  • DEFINE_enum()
  • DEFINE_list()
  • DEFINE_float()

Ebenso gut wie DEFINE_multi_integer(), DEFINE_multi_string() und DEFINE_multi_enum() für die Eingabe mit mehreren Argumenten. Außerdem Laufen --help, --helpfullusw. drucken die vorhandenen Flags und ihre Beschreibungen in verschiedenen Formaten.

Sehen Sie sich unseren praxisnahen, praktischen Leitfaden zum Erlernen von Git an, mit Best Practices, branchenweit akzeptierten Standards und einem mitgelieferten Spickzettel. Hören Sie auf, Git-Befehle zu googeln und tatsächlich in Verbindung, um es!

Mit der Bibliothek können Sie auch Validierungen definieren – sowohl in Bezug auf den Bereich, als auch auf ganzzahlige Werte mit einem upper_bound or lower_bound Das ist akzeptabel und das Ausführen beliebiger Methoden zur Überprüfung der Werte:

def validate_name(value):
    return len(value) > 15

flags.register_validator('name',
                         validate_name,
                         message='Name is over 15 characters long.',
                         flag_values=FLAGS)

Fassen Sie diese in einem konkreten Beispiel zusammen:

from absl import flags
import sys

flags.DEFINE_string('name', 'User', 'The name of the user.')
flags.DEFINE_integer('tasks', 0, 'The number of tasks a user has.', lower_bound=0)

FLAGS = flags.FLAGS
FLAGS(sys.argv)

print(f"{FLAGS.name} has {FLAGS.tasks} tasks to work on.")
$ python flags.py --name=John --tasks=5
John has 5 tasks to work on.
$ python flags.py --name=John --tasks=-1

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_flag.py", line 180, in _parse
    return self.parser.parse(argument)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_argument_parser.py", line 168, in parse
    raise ValueError('%s is not %s' % (val, self.syntactic_help))
ValueError: -1 is not a non-negative integer
...

Das argparse-Modul

Das argparse-Modul ist seit Python 3.2 verfügbar und eine Erweiterung des optparse Modul, das bis Python 2.7 existiert. Die Python-Dokumentation enthält eine API-Beschreibung und ein Tutorial, das alle Methoden im Detail behandelt.

Das Modul bietet eine Befehlszeilenschnittstelle mit einer standardisierten Ausgabe, während die beiden erstgenannten Lösungen einen Großteil der Arbeit in Ihren Händen lassen. argparse ermöglicht die Überprüfung fester und optionaler Argumente, wobei der Name entweder im kurzen oder langen Stil überprüft wird. Als standardmäßiges optionales Argument enthält es -h, zusammen mit seiner Langversion --help. Dieses Argument wird von einer Standardhilfemeldung begleitet, die die akzeptierten Argumente beschreibt.

Der folgende Code zeigt die Parser-Initialisierung und die Ausgabe unten zeigt den Basisaufruf, gefolgt von der Hilfemeldung. Im Gegensatz zu den Python-Aufrufen, die wir in den vorherigen Beispielen verwendet haben, denken Sie bei diesen Beispielen daran, Python 3 zu verwenden:


import argparse


parser = argparse.ArgumentParser()
parser.parse_args()
$ python3 arguments-argparse-basic.py 
$ python3 arguments-argparse-basic.py -h
usage: arguments-argparse-basic.py [-h]

optional arguments:
  -h, --help  show this help message and exit
$ python3 arguments-argparse-basic.py --verbose
usage: arguments-argparse-basic.py [-h]
arguments-argparse-basic.py: error: unrecognized arguments: --verbose

Im nächsten Schritt fügen wir der Hilfenachricht für unsere Benutzer eine benutzerdefinierte Beschreibung hinzu. Die Initialisierung des Parsers auf diese Weise ermöglicht einen zusätzlichen Text. Der folgende Code speichert die Beschreibung im text Variable, die explizit an die übergeben wird argparse Klasse als die description Parameter. Wenn Sie diesen Code unten aufrufen, können Sie sehen, wie die Ausgabe aussieht:


import argparse


text = 'This is a test program. It demonstrates how to use the argparse module with a program description.'


parser = argparse.ArgumentParser(description=text)
parser.parse_args()
$ python3 arguments-argparse-description.py --help
usage: arguments-argparse-description.py [-h]

This is a test program. It demonstrates how to use the argparse module with a
program description.

optional arguments:
  -h, --help  show this help message and exit

Als letzten Schritt fügen wir ein optionales Argument mit dem Namen hinzu -V, das über ein entsprechendes langes Stilargument mit dem Namen verfügt --version. Dazu verwenden wir die Methode add_argument() dass wir mit drei Parametern aufrufen (angezeigt für --version, nur):

  • Der Name des Parameters: --version
  • Der Hilfetext für den Parameter: help="show program version"
  • Aktion (ohne Zusatzwert): action="store_true"

Der Quellcode dafür wird unten angezeigt. Einlesen der Argumente in die aufgerufene Variable args erfolgt über die parse_args() Methode aus dem parser Objekt. Beachten Sie, dass Sie sowohl die Kurz- als auch die Langversion in einem Anruf einreichen. Abschließend überprüfen Sie, ob die Attribute vorhanden sind args.V or args.version werden gesetzt und geben die Versionsmeldung aus:


import argparse


parser = argparse.ArgumentParser()
parser.add_argument("-V", "--version", help="show program version", action="store_true")


args = parser.parse_args()


if args.version:
    print("This is myprogram version 0.1")
$ python3 arguments-argparse-optional.py -V
This is myprogram version 0.1
$ python3 arguments-argparse-optional.py --version
This is myprogram version 0.1

Das --version Für das Argument muss kein Wert in der Befehlszeile angegeben werden. Deshalb setzen wir das Aktionsargument auf "store_true". In anderen Fällen benötigen Sie möglicherweise einen zusätzlichen zugewiesenen Wert, beispielsweise wenn Sie ein bestimmtes Volumen, eine bestimmte Höhe oder Breite angeben. Dies wird im nächsten Beispiel gezeigt. Bitte beachten Sie, dass standardmäßig alle Argumente als Zeichenfolgen interpretiert werden:


import argparse


parser = argparse.ArgumentParser()


parser.add_argument("--width", "-w", help="set output width")


args = parser.parse_args()


if args.width:
    print("Set output width to %s" % args.width)

Hier zeigen wir, was passiert, wenn unterschiedliche Argumentwerte übermittelt werden. Dazu gehören sowohl die Kurz- als auch die Langversion, sowie die Hilfemeldung:

$ python3 arguments-argparse-optional2.py -w 10
Set output width to 10
$ python3 arguments-argparse-optional2.py --width 10
Set output width to 10
$ python3 arguments-argparse-optional2.py -h
usage: arguments-argparse-optional2.py [-h] [--width WIDTH]

optional arguments:
  -h, --help            show this help message and exit
  --width WIDTH, -w WIDTH
                        set output width

Das getopt-Modul

Wie Sie vielleicht schon bemerkt haben, ist die sys Das Modul teilt die Befehlszeilenzeichenfolge nur in einzelne Facetten auf. Der Python getopt-Modul geht noch etwas weiter und erweitert die Trennung der Eingabezeichenfolge durch Parametervalidierung. Basierend auf getopt C-Funktion ermöglicht sowohl kurze als auch lange Optionen, einschließlich einer Wertzuweisung.

In der Praxis erfordert es die sys Modul, um Eingabedaten ordnungsgemäß zu verarbeiten. Dazu müssen sowohl die sys Modul und die getopt Modul müssen vorher geladen werden. Als nächstes entfernen wir aus der Liste der Eingabeparameter das erste Listenelement (siehe Code unten) und speichern die verbleibende Liste der Befehlszeilenargumente in der aufgerufenen Variablen argument_list:


import getopt, sys


full_cmd_arguments = sys.argv


argument_list = full_cmd_arguments[1:]

print argument_list

Die Argumente in argument_list kann jetzt mit analysiert werden getopts() Methode. Aber bevor wir das tun, müssen wir es erzählen getopts() welche Parameter gültig sind. Sie sind wie folgt definiert:

short_options = "ho:v"
long_options = ["help", "output=", "verbose"]

Dies bedeutet, dass wir diese Argumente zusammen mit einigen zusätzlichen Informationen für gültig halten:

------------------------------------------
long argument   short argument  with value
------------------------------------------
--help           -h              no
--output         -o              yes
--verbose        -v              no
------------------------------------------

Sie haben vielleicht bemerkt, dass die o der kurzen Option wurde ein Doppelpunkt vorangestellt, :. Das sagt getopt dass dieser Option ein Wert zugewiesen werden soll.

Dies ermöglicht es uns nun, eine Liste von Argumenten zu verarbeiten. Der getopt() Für die Methode müssen drei Parameter konfiguriert werden – die Liste der tatsächlichen Argumente von argvsowie die gültigen kurzen und langen Optionen (im vorherigen Codeausschnitt gezeigt).

Der Methodenaufruf selbst wird in einer Try-Catch-Anweisung gespeichert, um Fehler während der Auswertung abzudecken. Eine Ausnahme wird ausgelöst, wenn ein Argument entdeckt wird, das nicht Teil der zuvor definierten Liste ist. Das Python-Skript gibt die Fehlermeldung auf dem Bildschirm aus und wird mit Fehlercode 2 beendet:

try:
    arguments, values = getopt.getopt(argument_list, short_options, long_options)
except getopt.error as err:
    
    print (str(err))
    sys.exit(2)

Abschließend werden die Argumente mit den entsprechenden Werten in den beiden genannten Variablen gespeichert arguments und values. Jetzt können Sie diese Variablen ganz einfach in Ihrem Code auswerten. Wir können a verwenden for-loop, um die Liste der erkannten Argumente zu durchlaufen, einen Eintrag nach dem anderen.


for current_argument, current_value in arguments:
    if current_argument in ("-v", "--verbose"):
        print ("Enabling verbose mode")
    elif current_argument in ("-h", "--help"):
        print ("Displaying help")
    elif current_argument in ("-o", "--output"):
        print (("Enabling special output mode (%s)") % (current_value))

Unten sehen Sie die Ausgabe der Ausführung dieses Codes. Wir zeigen, wie das Programm sowohl mit gültigen als auch mit ungültigen Programmargumenten reagiert:

$ python arguments-getopt.py -h
Displaying help
$ python arguments-getopt.py --help
Displaying help
$ python arguments-getopt.py --output=green --help -v
Enabling special output mode (green)
Displaying help
Enabling verbose mode
$ python arguments-getopt.py -verbose
option -e not recognized

Der letzte Aufruf unseres Programms mag zunächst etwas verwirrend wirken. Um es zu verstehen, müssen Sie wissen, dass die Kurzschriftoptionen (manchmal auch Flags genannt) zusammen mit einem einzelnen Bindestrich verwendet werden können. Dadurch kann Ihr Werkzeug viele Optionen einfacher akzeptieren. Zum Beispiel anrufen python arguments-getopt.py -vh ist das gleiche wie anrufen python arguments-getopt.py -v -h. Also im letzten Aufruf oben, der getopt Das Modul ging davon aus, dass der Benutzer versuchen wollte, zu bestehen -e als Option, was ungültig ist.

Zusammenfassung

In diesem Artikel haben wir viele verschiedene Methoden zum Abrufen von Befehlszeilenargumenten in Python gezeigt, einschließlich der Verwendung sys, getopt und argparse. Die Funktionalität dieser Module variiert, einige bieten viel mehr als andere. sys ist völlig flexibel, während beide getoptund argparse erfordern eine gewisse Struktur. Im Gegensatz dazu decken sie die meisten komplexen Arbeiten ab sys überlässt es Ihnen. Nachdem Sie die bereitgestellten Beispiele durchgearbeitet haben, sollten Sie feststellen können, welches Modul am besten zu Ihrem Projekt passt.

In diesem Artikel haben wir nicht über andere Lösungen wie die gesprochen docopts Modul, wir haben es gerade erwähnt. Dieses Modul verfolgt einen völlig anderen Ansatz und wird in einem der nächsten Artikel ausführlich erläutert.

Bibliographie

Zeitstempel:

Mehr von Stapelmissbrauch