Lerne Coding
Eigene CLI Befehle in Python erstellen!
06.10.2021

Python einen CLI Command erstellen

Inhaltsverzeichnis
[[TABLE OF CONTENTS]]
access_timeGeschätzte Lesezeit ca. Minuten

In diesem Beitrag arbeite ich zusammen mit dem Youtuber "Programmieren mit Chris". Wir haben uns zusammengetan, um euch näher zu bringen, wie ihr eigene Befehle für euer Betriebsystem schreiben könnt. Im ersten Teil dieses Beitrages findet ihr das Youtube-Video. Schaut es am besten als erstes an, um einen Eindruck von dem Thema "Python CLI Commandos erstellen" zu bekommen. Im Text findet ihr noch weitere Details dazu.

Eingaben beim Starten einlesen | argparse | Tutorial

Als Ergänzung zu diesem Video findest du die wichtigsten Inhalte und weitere Tipps und Tricks in den nachfolgenden Abschnitten.

Command Line Arguments parsen in Python

Es gibt verschiedene Möglichkeiten um Command Line Arguments in Python zu parsen. Die Einfachste ist, einen eigenen kleinen Parser zu schreiben, der eine Key-Value-Paar Zuordnung macht.

Diesen Weg gehe ich zum Beispiel bei unserem kleinen Begrüßungsprogramm. Alle Argumente sollen bei uns mit der Syntax -- beginnen, somit haben wir einen Trennpunkt, um zu identifizieren, wo das nächste Element beginnt.

Unser Command könnte zum Beispiel so aussehen:

greeting --name Felix --age 23

So könnte der Code aussehen den wir Parsen werden.

Diesen haben wir mit einem Decorator eingerichtet. Der Vorteil davon ist, dass wir diese Funktion nun auf jede beliebige Funktion anwenden können. Natürlich existieren noch weitere Parser, welche es als fertiges Modul gibt, sowie für aufwändigere Befehle, die auch Listen und andere Optionen haben sollen. Für kleinere Anwendungen kann es ein selbst geschriebener aber auch schon tun.

In dem Dictionary mit dem Variablennamen args speichern wir später unsere Key-Value Zuordnung ab, die wir an die eigentliche Funktion zurückgeben. In der Variable name speichern wir unsere Namen zwischen, also so etwas wie --name oder --age kann dort abgelegt werden und wird anschließend seinem Wert zugeordnet.

Bei unserem Parser darf jeder name nur einen festen Wert haben. Mehrere Werte mit Lehrstelle zu trennen ist dort nicht möglich. Eine Liste von Namen könnte man Kommasepariert angeben und dann aufteilen, um eine Liste zu erhalten.

def parseme(func):
    def wrapper(arguments): # Eigentliche Funktion wo wir unsere Variable durchreichen können.
        name = [] # In dieser Variable speichern wir eine Liste der Namen
        args = {}

        for value in arguments:
            if "--" in value: 
                name.append(value)
            elif len(name) > 0 and name[-1] not in args:
                args.update({name[-1]:value})

        return func(args)
    return wrapper

Ein kleines Begrüßungsprogramm

Um unseren Argumente-Parser zu testen, haben wir nun ein kleines Programm geschrieben, welches unsere Argumente entgegennimmt (--age und --name). Daraus entsteht ein entsprechender Begrüßungstext.

import sys

#  ... parseme function, hier einfügen. 

@parseme
def greeting(args):
    if "--name" in args and "--age" in args:
        print('Hallo mein {} jähriger Freund {}!'.format(args['--age'],args['--name']))
    elif "--name" in args:
        print('Hallo mein Freund {}!'.format(args['--name']))
    elif "--age" in args:
        print('Hallo mein unbekannter Freund, von dem ich nur weiß das er {} ist!'.format(args['--age']))
    else:
        print('Hallo mein unbekanter Freund!')

if __name__ == "__main__":
    greeting(sys.argv)

Anschließend können wir nun die Befehle in verschiedenen Kombinationen aufrufen und erhalten entsprechend unterschiedliche Resultate.

python main.py --name Felix --age 23

# Antwort: Hallo mein 23 jähriger Freund Felix!

python main.py --name Felix 

# Antwort: Hallo mein Freund Felix!

python main.py --age 23

# Antwort: Hallo mein unbekannter Freund, von dem ich nur weiß, dass er 23 ist!

python main.py

# Antwort: Hallo mein unbekanter Freund!

Kleiner Tipp: Du kannst auch mittels Python farbige Ausgaben im Terminal erstellen. Mehr dazu findest du in dem Artikel: "Farben im Terminal für Python mit Colorama"

Welche Module sind nützlich, um einen CLI Command zu erstellen?

Es gibt verschiedene Module die du verwenden kannst, um dir die Arbeit mit der CLI zu vereinfachen oder dir zusätzliche Funktionalitäten zu liefern, wie zum Beispiel ein Auswahlmenü oder Checkboxen, wo du mehrere Punkte aktivieren kannst.

ArgParse - Das interne Modul mit den wichtigsten Basics

Das Modul ArgParse hat einen großen entscheidenden Vorteil gegenüber dem Arbeiten mit sys.argv. Du musst nicht selber einen Parser schreiben und dieses Python Modul ist von Haus aus ab Python 3 enthalten. Davor gab es das Modul optparse für Python 2.7 und älter.

Unsere Greeting-Befehle von oben würden mit dem ArgParse Modul zum Beispiel wie folgt aussehen. Der Vorteil von Argparse ist, dass undefinierte Argumente auch Fehler schmeißen und so eine falsche Verwendung verhindert wird. Desweiteren kannst du zwischen notwendigen und optionalen Argumenten unterscheiden, und auch positionsabhängige Argumente erstellen.

import argparse

def greeting(args):
    if args.name and args.age:
        print('Hallo mein {} jähriger Freund {}!'.format(args.age,args.name))
    elif args.name:
        print('Hallo mein Freund {}!'.format(args.name))
    elif args.age:
        print('Hallo mein unbekannter Freund, von dem ich nur weiß, dass er {} ist!'.format(args.age))
    else:
        print('Hallo mein unbekanter Freund!')

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Greeting Application')

    parser.add_argument('--name', type=str, help='Wie heißt du?')
    parser.add_argument('--age', type=int, help='Wie alt bist du?')

    greeting(parser.parse_args())

Das ArgParse Modul hat den Vorteil, dass du dort auch direkt eine Hilfe-Funktion hast, die die Befehle nachdem, ob sie notwendig sind oder nicht, auflistet.

-> % python argparse-example.py --help      
usage: argparse-example.py [-h] [--name NAME] [--age AGE]

Greeting Application

optional arguments:
  -h, --help   show this help message and exit
  --name NAME  Wie heißt du?
  --age AGE    Wie alt bist du?

Die Dokumentation von ArgParse findest du hier: https://docs.python.org/3.9/library/argparse.html

Es ist auf jeden Fall, um eine Übersicht zu bekommen, ein Blick wert!

Pick - Wähle eine Option aus!

Mit dem Pick-Modul, kannst du aus einer Liste von Optionen, eine Option auswählen. So kannst du für deine Nutze dein Command Line Tool noch intuitiver und interessanter gestalten.

Du kannst mit verschiedenen Modi arbeiten:

  • Auswahl eines Listenitems
  • Auswahl von mehreren Elementen
  • Begrenzung der Elemente die ausgewählt werden können.

So könntest du dann zum Beispiel in deinem Commando eine Auswahl zwischen verschiedenen Befehlen gestalten, ohne dass der Nutzer Diese dann selbst eingeben müsste.

Auf dem Bild ist der Ablauf zu sehen, wie man mittels Pick eine Option in einem Terminal auswählen kann.
Github Logowong2/pick
682 19 61

create curses based interactive selection list in the terminal

Click - Command Line Interface Creation Kit

Click beschreibt sich selbst als Toolkit, um einfach und mit viel Spaß ein Command Line Tool zu erstellen und Frustation zu vermeiden. Durch viele Dekoratoren kannst du dir die Erstellung eines Command Line Tools vereinfachen und zum Beispiel sehr einfach einen Hilfe-Command erstellen.

Wie könnte das an unserem Beispiel von oben aussehen? Ich habe euch einmal das ganze als Beispiel geschrieben. Wie du siehst, können wir direkt Standardwerte und einen Hilfetext angeben, und wir müssen auch nicht mehr die Argumente parsen. Logisch, das Modul übernimmt für uns diese ganze Arbeit. Natürlich wird der Code genau genommen so auch größer, da das externe Modul geladen werden muss. Aber dadurch haben wir in kürzerer Zeit mehr Möglichkeiten ein Ergebnis zu erreichen.

import click

@click.command()
@click.option('--age', default=0, help='Wie alt bist du?')
@click.option('--name', default='',help='Wie heißt du?')
def greeting(age, name):

    if age and name:
        click.echo('Hallo mein {} jähriger Freund {}!'.format(age,name))
    elif name:
        click.echo('Hallo mein Freund {}!'.format(name))
    elif age:
        click.echo('Hallo mein unbekannter Freund, von dem ich nur weiß, dass er {} ist!'.format(age))
    else:
        click.echo('Hallo mein unbekanter Freund!')

if __name__ == '__main__':
    greeting()

Unser Help-Commando für dieses Tool sieht zum Beispiel so aus:

-> % python test-click.py --help               
Usage: test-click.py [OPTIONS]

Options:
  --age INTEGER  Wie alt bist du?
  --name TEXT    Wie heißt du?
  --help         Show this message and exit.

Mehr zu Click findet ihr in der offiziellen Dokumentation: https://click.palletsprojects.com/

Wie kannst du das Python Script als Befehle in deinem System integrieren?

Nun wo du dein perfektes CLI Tool fertiggestellt hast, möchtest du natürlich einen einfachen Zugriff darauf haben. Egal in welchem Ordner du dich befindest. Also bietet es sich an, einen richtigen Befehl daraus zu machen.

Einrichtung unter Linux und MacOS

Um damit zu starten, benötigen wir in unserem Script als erstes eine Shebang-Zeile. Die übliche Shebang-Zeile für Python sieht so aus: #! /usr/bin/python. Je nach dem welche Version du nutzt und wo du Python installiert hast, ist Diese bei dir ggf. abweichend.

Mittels dem where Befehle kannst du auf jeder Command Line, sei es das Terminal von MacOS oder Linux, herausfinden, wo dein Python liegt. Dazu musst du einfach where python eingeben. Dann erhältst du den entsprechenden Pfad, den du verwenden solltest.

Was ist eine Shebang-Zeile?

Über die Shebang-Zeile kann ein System erkennen, über welche Programmiersprache, Scriptsprache, das Ganze ausgeführt werden soll. Normal schreibst du ja immer python oder python3 vor deinen Aufruf deiner Datei. Da wir darauf verzichten wollen, muss das System wissen, womit das Ganze auszuführen ist.

Einrichtung des Commandos

Nun kommen wir zu den Einstellungen die du umsetzen musst, um unsere Greeting-Anwendung unter Linux oder MacOS als Command zu verwenden. Ich mach die Änderungen/Anpassungen über die Command Line. Wichtig: Du musst dich in dem Verzeichnis befinden, in dem deine Datei für die nachfolgenden Befehle liegt. Mit dem cd Befehl kannst du auch dorthin navigieren.

  1. Als erstes müssen wir die Datei ausführbar machen. Das machen wir über den Befehl chmod +x dateiname.py
  2. Umbennen & Verschieben der Datei. Nun müssen wir die Datei umbennen und in das globale Verzeichnis für Befehle verschieben. Mit dem Befehl verschieben wir die Datei und bennen sie nun greeting - mv ./main.py /usr/local/bin/greeting
  3. Nun können wir den Befehl greeting mit unseren Argumenten verwenden.

Einrichtung unter Windows

Unter Windows läuft die Einrichtung von einem Commando etwas komplizierter ab, als bei Linux/MacOS/Unix.

Lege dir einen Ordner an wo du deine Python Scripte alle sammelst, die du als Commando ausführen willst. Diesen musst du zu den PATH Umgebungsvariablen hinzufügen. Suche danach unter Windows einfach nach "Umgebungsvariablen". Dann erscheint ein Fenster der Systemeigenschaften, wo du auf den Button "Umgebungsvariablen" drücken musst. Dort kannst du den Pfad angeben, unter dem deine Python Scripte liegen. In meinem Fall zum Beispiel: C:\Users\fschu\python_data\ dort hinterlege ich nun unsere Datei greeting.py.

Auf dem Bild ist das Windows Interface zu sehen, wo du die Umgebungsvariablen bearbeiten kannst.
Auf dem Bild ist das Windows Interface zu sehen, wo du die Umgebungsvariablen bearbeiten kannst.

Anschließend kannst du deine Command Line einmal neustarten. Nun kannst du überall greeting.py eingeben. Allerdings ist diese Schreibweise noch nicht sonderlich schön, also musst du noch die Systemvariable PATHEXT bearbeiten und die Erweiterung .PY hinzufügen. Nun kannst du nach einem erneuten Neustart von der Command Line einfach nur noch greeting eingeben.

Ansicht des Systemvariable Bearbeiten Fensters, wo du die Pathext-Variable Bearbeiten kannst.
Ansicht des Systemvariable Bearbeiten Fensters, wo du die Pathext-Variable Bearbeiten kannst.
Achtung!

Manchmal kann es bei dem System und Umgebungsvariablen notwendig sein, deinen Computer neuzustarten, damit die Änderungen wirksam wird.

Zusammenfassung

Mittels Python und den vielen zusätzlichen Modulen, kannst du viel mit der CLI bewerkstelligen. Zudem ist es häufig zeitsparender, wenn es nur um die Daten geht und nicht darum, mit PyQT oder Tinker noch ein schönes Interface zu gestalten. Eine super Aufgabe die du als Übung umsetzen könntest, wäre ein Text-Adventure im Terminal.

Bildquelle - Vielen Dank an die Ersteller:innen für dieses Bild
Kommentare zum Artikel

Es sind noch keine Kommentare vorhanden? Sei der/die Erste und verfasse einen Kommentar zum Artikel "Eigene CLI Befehle in Python erstellen!"!

Kommentar schreiben

Vom Autor Empfohlen
close