HOWTO · Python
Wie man Bash-Skripte in Python ausführt
Lernen Sie, wie man Bash-Skripte mit Python ausführt, mit unserem umfassenden Leitfaden. Erforschen Sie Methoden wie subprocess, os.system und subprocess.Popen, um Bash-Befehle effizient auszuführen. Verbessern Sie Ihre Automatisierungsfähigkeiten und optimieren Sie Abläufe, indem Sie Bash-Skripte in Ihre Python-Anwendungen integrieren.
Auf dieser Seite
Verwenden Sie subprocess.run für die meisten Bash-Skripte, die abgeschlossen sein sollen, bevor Python fortfährt. Damit können Sie Argumente einzeln übergeben, stdout und stderr erfassen und den returncode des Prozesses prüfen. Bash muss installiert und für Python verfügbar sein. Dieser Ansatz hängt daher von der Hostumgebung ab und ist auf Systemen ohne Bash nicht portabel. Das folgende Beispiel erstellt eine eigene Skriptdatei, übergibt einen Namen als Argument und gibt das erfasste Ergebnis aus.
Methode 1: Das Modul subprocess verwenden
Dieses eigenständige Beispiel erstellt ein kleines Bash-Skript, übergibt ihm ein Argument und erfasst beide Ausgabeströme. Das Bash-Skript gibt eine Begrüßung aus; anschließend gibt Python den erfassten Text und den Prozessstatus aus. Die Begrüßung und die Beschriftung „Return code“ bleiben im unveränderten Beispiel auf Englisch.
import subprocess
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as directory:
script_path = Path(directory) / "greet.sh"
script_path.write_text(
'#!/usr/bin/env bash\nprintf "Hello, %s!\\n" "$1"\n',
encoding="utf-8",
)
result = subprocess.run(
["bash", str(script_path), "Ada"],
capture_output=True,
text=True,
check=False,
)
print(result.stdout, end="")
print(f"Return code: {result.returncode}")
Hello, Ada!
Return code: 0
Die Argumentliste übergibt den Skriptpfad und Ada als separate Argumente. Mit dem Standardwert shell=False startet Python Bash direkt, anstatt die Liste von einer Shell parsen zu lassen. Dadurch wird das Parsen dieser Argumente durch eine Shell vermieden, doch das ist keine allgemeine Sicherheitsgarantie: Validieren Sie Eingaben und berücksichtigen Sie, was das Skript selbst tut. Ein returncode von null bedeutet Erfolg; ein Wert ungleich null bedeutet, dass der Prozess einen Fehler gemeldet hat. stderr ist ein separater Ausgabestrom für Diagnosemeldungen. Text in diesem Strom bedeutet für sich genommen nicht, dass der Befehl fehlgeschlagen ist. Mit capture_output=True stehen sowohl stdout als auch stderr im Ergebnisobjekt zur Verfügung.
Methode 2: os.system verwenden
Verwenden Sie os.system nur, wenn ein einfacher Befehl ausreicht und Python dessen Ausgabe nicht erfassen muss. Die Funktion nimmt eine einzelne Befehlszeichenfolge entgegen, führt sie über eine System-Shell aus und leitet die Ausgabeströme des Befehls an die Standardausgabeströme des umgebenden Prozesses weiter. Der Rückgabewert hängt vom System ab und kann den Prozessstatus codieren, statt dem Exitcode des Kindprozesses zu entsprechen. Behandeln Sie ihn daher nicht als portablen, direkten Exitcode. Ein Ergebnisobjekt mit stdout oder stderr stellt os.system nicht bereit. Erstellen Sie die Befehlszeichenfolge nicht aus nicht vertrauenswürdigen Eingaben, denn durch das Shell-Parsing können diese eine besondere Bedeutung erhalten. Für separate Argumente, erfasste Ausgabeströme und eine zuverlässige Statusprüfung ist subprocess vorzuziehen.
Methode 3: subprocess.Popen verwenden
Wählen Sie subprocess.Popen, wenn Sie eine laufende Prozessinstanz genauer steuern müssen, etwa um ihre Lebensdauer zu verwalten oder Pipes zu verbinden. Für einen begrenzten Datenaustausch setzen Sie beim Erstellen des Prozesses stdin=subprocess.PIPE und rufen anschließend communicate(input=...) auf, um Eingaben zu senden und die erfassten Ausgabeströme nach Abschluss des Prozesses einzulesen. Ohne diese stdin-Pipe kann communicate(input=...) keine Daten an den Kindprozess senden. Die Ausgabe wird dabei nicht in Echtzeit geliefert. Wenn Sie Pipes für beide Ausgabeströme erstellen, lesen Sie sie mit communicate() vollständig aus; wartet der Elternprozess, während sich eine Pipe füllt, kann es zu einem Deadlock kommen. Für eine Live-Ausgabe müssen Sie die Ausgabeströme gezielt lesen und leeren, statt communicate() als Streaming-Schnittstelle zu behandeln. Das genaue Verhalten der Pipes hängt von Plattform und Prozess ab.
Fazit
Für ein Bash-Skript, das vollständig ausgeführt werden soll, ist subprocess.run meist die klarste Wahl: Übergeben Sie eine Liste, erfassen Sie bei Bedarf die Ausgabeströme und verwenden Sie returncode, um den Erfolg zu bestimmen. os.system eignet sich für einfache Shell-Befehle ohne Ausgabeverarbeitung; subprocess.Popen ist sinnvoll, wenn eine ausdrückliche Prozesssteuerung oder Kommunikation erforderlich ist. Prüfen Sie, ob Bash in der Umgebung installiert und verfügbar ist, in der das Python-Programm läuft. Ein Skript lässt sich nur starten, wenn Python die Bash-Datei findet.
Häufig gestellte Fragen
-
Wie führt man ein Bash-Skript am besten aus Python aus?
Verwenden Siesubprocess.runfür die meisten Skripte, die abgeschlossen sein sollen, bevor Python fortfährt. Die Funktion unterstützt Argumentlisten, erfasste Ausgabeströme und einen Prozessstatus überreturncode. -
Wie erfasse ich die Ausgabe eines Skripts?
Setzen Sie beisubprocess.runcapture_output=Trueundtext=Trueund lesen Sie anschließendstdoutundstderraus dem zurückgegebenen Objekt. Verbinden Sie beiPopendie benötigten Pipes und rufen Siecommunicate()auf, um die Ausgabeströme nach Abschluss des Prozesses einzulesen. Dabei wird die Ausgabe erfasst, aber nicht live übertragen.stderrkann Diagnosemeldungen enthalten, auch wenn der Prozess erfolgreich ist. Prüfen Sie seinen Status daher mitreturncode. -
Ist das Übergeben einer Liste sicher?
Mitshell=Falseverhindert eine Liste, dass eine Shell die übergebenen Argumente parst. Das senkt das Risiko einer Shell-Injection, macht aber nicht jedes Skript und jede Eingabe sicher. Validieren Sie Werte und berücksichtigen Sie das Verhalten des Skripts. -
Kann ich einem Bash-Skript Argumente übergeben?
Ja. Fügen Sie jedes Argument nach dem Skriptpfad als separates Element in diesubprocess-Argumentliste ein.os.systemnimmt eine einzelne Befehlszeichenfolge entgegen und bietet daher keine gleichwertige strukturierte Übergabe von Argumenten. -
Wie kann ich dem Skript Eingaben bereitstellen?
Verwenden Siesubprocess.runmitinput=...für einen einfachen, begrenzten Datenaustausch. Wenn Sie den Prozess genauer steuern müssen, verwenden SiePopenmitstdin=subprocess.PIPEundcommunicate(input=...).communicate()sendet die Eingabe und liest die Prozessausgabeströme ein, nachdem der Kindprozess beendet ist.