# 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](https://www.ionos.de/digitalguide/websites/web-entwicklung/internet-programmiersprachen/). 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.

## `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:

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

Die Ausgabe ist dann diese:

```python
hallo
```

- `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“:

```python
print("Heute ist das Wetter gut")
```

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

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

Die entsprechende Ausgabe wird dann so aussehen:

```python
Heute ist das Wetter gut
```

## 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:

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

## `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:

```python
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)
```

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:

```python
Die Standardausgabe lautet: hallo
Dies ist der Standardfehler:
```

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:

```python
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)
```

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

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

## 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:

```python
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)
```

Unsere Ausgabe sieht dann so aus:

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

## 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:

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

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](https://www.ionos.de/digitalguide/websites/web-entwicklung/python-classes/), 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:

```python
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}")
```

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](https://www.ionos.de/hosting/deploy-now "Deploy Now von IONOS") von IONOS profitieren Sie von einem schnelleren Setup, optimierten Workflows und einer hervorragenden Skalierbarkeit. Finden Sie den passenden Tarif für Ihre Zwecke!


This is a markdown version of: [https://www.ionos.de/digitalguide/websites/web-entwicklung/python-subprocess/](https://www.ionos.de/digitalguide/websites/web-entwicklung/python-subprocess/) for AI/LLM consumption.