Python subprocess: Externe Befehle und Programme ausführen

Python subprocess ist ein Modul, mit dem Sie externe Programme innerhalb des Codes ansteuern, ausführen und auswerten können. Die beiden wichtigsten Funktionen dieses Tools sind run() und Popen().

Was ist Python subprocess?

Das Python-Modul subprocess gehört seit Version 2.4 fest zum Inventar der Programmiersprache. Es handelt sich dabei um ein sehr umfangreiches und leistungsstarkes Tool, das Sie nutzen können, um andere Programme oder Befehle innerhalb Ihres Codes auszuführen. Dabei ist es nicht nur möglich, Programme zu öffnen, sondern auch den Datenfluss zu kontrollieren und anzupassen. Python subprocess bietet zahlreiche Methoden und Funktionen, von denen wir uns die wichtigsten in diesem Artikel anschauen und anhand praktischer Beispiele erklären.

Managed Nextcloud by IONOS Cloud
Teamarbeit in der eigenen Cloud
  • Vollständige Datensouveränität in deutschen Rechenzentren
  • Managed Service ohne Administrationsaufwand
  • File-Sharing, Dokumentenbearbeitung & Kommunikation

subprocess: Funktionsweise mit run()

Vorher ist es allerdings sinnvoll, einen Blick auf den Aufbau und die grundsätzliche Funktionsweise von Python subprocess zu werfen. Das Modul wird verwendet, um Unterprozesse auszuführen. Python funktioniert dabei in der Eltern-Kind-Hierarchie als übergeordneter Part (Parent Process), der einen untergeordneten Prozess erstellt. Die Funktion, die innerhalb des Moduls am häufigsten verwendet wird, ist run(). Diese erlaubt es Ihnen, einen Prozess über Python zu starten und beginnt weitere Schritte erst, wenn dieser vollständig durchgeführt wurde.

Beispiel für die Funktionsweise von Python subprocess mit run()

Diese Funktion nutzen wir nun auch für unser erstes kleines Beispiel, mit dem wir die Funktionsweise von Python subprocess verdeutlichen können. Dafür importieren wir zunächst die Module subprocess und sys und führen dann eine einfache Aufforderung aus. Der entsprechende Code sieht so aus:

import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "print('hallo')"])
python

Die Ausgabe ist dann diese:

hallo
python
  • subprocess.run: Dies ist die eigentliche Funktion. Sie erhält eine Liste mit Zeichenfolgen, die den Befehl enthalten, der ausgeführt werden soll. run() führt dann ein neues Python-Programm aus.
  • sys.executable: Bei sys.executable handelt es sich um den absoluten Pfad, der zur Python-Datei führt, mit der Sie Ihr Programm ursprünglich aufgerufen haben. Ein solcher Pfad könnte beispielhaft so aussehen /local/nutzer/bin/beispiel.
  • -c: -c ist eine Befehlszeilenoption mit der die genannte Zeichenfolge zur Ausführung übergeben wird. Für unser Beispiel ist dies ein Programm, das das Wort „hallo“ ausgibt.

Python subprocess mit einem Skript ausführen

Um zu testen, wie Sie das Modul für ein eigens angefertigtes Skript verwenden, können Sie das folgende Beispiel ausprobieren. Dafür erstellen Sie zunächst ein einfaches Skript im .py-Format und speichern es als „beispielskript.py“:

print("Heute ist das Wetter gut")
python

Um diese Datei nun mit Python subprocess auszuführen, nutzen Sie den folgenden Code:

import subprocess
result = subprocess.run(["python", "beispielskript.py"], capture_output=True, text=True)
print(result.stdout)
python

Die entsprechende Ausgabe wird dann so aussehen:

Heute ist das Wetter gut
python

Externe Programme öffnen

Grundsätzlich ist es mit Python subprocess und der Funktion run() möglich, ein beliebiges Programm zu öffnen. Die einzige Voraussetzung dafür ist, dass Sie den genauen Namen oder den Pfad kennen, unter dem dieses Programm auf Ihrem System zu finden ist. Im folgenden Code öffnen wir beispielsweise Notepad:

import subprocess
subprocess.run(["notepad"])
python

CompletedProcess und Erfassung externer Ausgaben

Nach diesen einfachen Beispielen befassen wir uns nun mit der Erfassung einer externen Ausgabe. Dabei führen Sie ein externes Programm mit Python subprocess wie oben aus, lassen sich allerdings ein sogenanntes CompletedProcess-Objekt zurückgeben. Die dafür notwendigen Anpassungen haben wir weiter oben in einem Beispiel schon einmal kurz eingebaut, nun gehen wir näher darauf ein. Unser Ausgangspunkt ist wieder unser erster Code. Diesen passen wie nun aber an:

import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "print('hallo')"], capture_output=True, text=True)
print("Die Standardausgabe lautet:", result.stdout)
print("Dies ist der Standardfehler:", result.stderr)
python

Erneut weisen wir damit das System an, die Zeichenfolge „hallo“ auszugeben. Dies erfolgt in einem untergeordneten Prozess. Neu sind allerdings die beiden Schlüsselwortargumente capture_output=True und text=True, die wir ebenfalls an run() übergeben. Wird die Anweisung ausgeführt und gibt es keine Fehler, erhalten Sie ein CompletedProcess-Objekt mit einer Bindung an result. Das Objekt enthält Informationen zum Exit-Code des Programms, das Sie ausführen lassen möchten, und gibt diese an result.stdout und result.stderr weiter. stdout bezeichnet die Standardausgabe, stderr mögliche Standardfehler. text=True nutzen wir dazu, um die Ausgabe als Zeichenfolge zu drucken. Da kein Standardfehler zu erwarten ist, lautet unser Ergebnis wie folgt:

Die Standardausgabe lautet: hallo
Dies ist der Standardfehler:
python

Um die Funktionsweise besser zu veranschaulichen, erstellen wir das nächste Beispiel so, dass stderr dieses Mal nicht leer bleibt. Der entsprechende Code ist dieser:

import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "raise ValueError('fehler')"], capture_output=True, text=True)
print("Die Standardausgabe lautet:", result.stdout)
print("Dies ist der Standardfehler:", result.stderr)
python

Während die Standardausgabe dieses Mal leer bleibt, gibt es für stderr nun eine Ausgabe:

Die Standardausgabe lautet:
Dies ist der Standardfehler: Traceback (most recent call last):
	File "<string>", line 1, in <module>
ValueError: fehler
python

Ausführung aus einer Funktion

Auch wenn Sie einen Befehl direkt in den Code einbauen möchten, bietet Ihnen Python subprocess diese Option. Der Code könnte in diesem Fall aussehen wie in diesem Beispiel:

import subprocess
result = subprocess.run(["C:/Users/name/anaconda3/python", "-c", "print('Diese Ausgabe wurde direkt aus einer Funktion übernommen')"], capture_output=True, text=True, shell=True)
print("Die Standardausgabe lautet:", result.stdout)
python

Unsere Ausgabe sieht dann so aus:

Die Standardausgabe lautet: Diese Ausgabe wurde direkt aus einer Funktion übernommen
python

Prozesse anhalten oder beenden

Ein weiterer sehr nützlicher Verwendungszweck von Python subprocess wird durch das Zusammenspiel von run() mit dem timeout-Argument erreicht. Es ermöglicht Ihnen, ein externes Programm anzuhalten, sofern seine Ausführung zu lange dauert. Dafür verwenden Sie die Funktion time.sleep. Der passende Code ist dieser:

import subprocess
import sys
result = subprocess.run([sys.executable, "-c", "import time; time.sleep(3)"], timeout=1)
python

Der untergeordnete Prozess nutzt time.sleep, um für drei Sekunden auszusetzen. Da Sie das System allerdings über timeout=1 angewiesen haben, nach einer Sekunde ein Timeout auszulösen, ist das Ergebnis eine TimeoutExpired-Ausnahme.

Python subprocess mit Popen()

Auch wenn run() die Funktion von Python subprocess ist, die am häufigsten genutzt wird, gibt es noch andere wichtige Klassen, die sehr nützlich sein können. Dazu gehört auch Popen(). Diese Klasse ist quasi der Unterbau von Python subprocess und in der Anwendung etwas komplexer als run(). Dafür erhalten Sie über Popen() allerdings mehr Kontrolle über die Ausführung und können mit dem Input und Output interagieren. Die Klasse verdankt ihren Namen einem UNIX-Befehl und steht für „pipe open“.

Beinahe alle Argumente, die Sie mit run() nutzen können, sind auch für Popen() zugelassen. Im Gegensatz zu run() wartet diese Funktion allerdings nicht bis ein Prozess abgeschlossen ist, sondern startet parallel einen zweiten. Die Funktionsweise können wir mit einem einfachen Beispiel verdeutlichen:

import subprocess
from time import sleep
def poll_and_read(process):
    print(f"Dies ist die Ausgabe nach poll(): {process.poll()}")
    print(f"Dies ist die Standardausgabe: {process.stdout.read().decode('utf-8')}")
process = subprocess.Popen(["python", "timer.py", "3"], stdout=subprocess.PIPE)
poll_and_read(process)
sleep(2)
poll_and_read(process)
sleep(2)
poll_and_read(process)
process.wait()
print(f"Exit-Code des Prozesses: {process.returncode}")
python

Hierbei nutzen wir die Methode .poll(), um zu überprüfen, ob der Prozess noch läuft oder bereits abgeschlossen ist. Solange er noch läuft, wird der Wert „none“ ausgegeben. Danach gibt die Methode den Exit-Code aus. Mit .read() sollen alle Bytes ausgelesen werden, die sich bisher unter .stdout befinden. Wenn Sie den Code ausführen, werden Sie zuerst den Wert „None“ erhalten und danach den Wert, der bisher in stdout enthalten ist. Dies geht so lange, bis der Prozess durchlaufen wurde. Dann erhält poll() den Wert „0“.

Tipp

Apps und Websites direkt mit GitHub deployen: Bei Deploy Now von IONOS profitieren Sie von einem schnelleren Setup, optimierten Workflows und einer hervorragenden Skalierbarkeit. Finden Sie den passenden Tarif für Ihre Zwecke!

War dieser Artikel hilfreich?
Page top