Die anderen Antworten hier erläutern angemessen die Sicherheitsvorbehalte, die auch in der subprocess
Dokumentation erwähnt werden. Darüber hinaus ist der Aufwand für das Starten einer Shell zum Starten des Programms, das Sie ausführen möchten, häufig unnötig und in Situationen, in denen Sie keine der Funktionen der Shell verwenden, definitiv albern. Darüber hinaus sollte Sie die zusätzliche versteckte Komplexität erschrecken, insbesondere wenn Sie mit der Shell oder den von ihr bereitgestellten Diensten nicht sehr vertraut sind.
Wenn die Interaktionen mit der Shell nicht trivial sind, benötigen Sie jetzt den Leser und Betreuer des Python-Skripts (das möglicherweise Ihr zukünftiges Selbst ist oder nicht), um sowohl Python- als auch Shell-Skript zu verstehen. Denken Sie daran, dass das Python-Motto "explizit ist besser als implizit"; Selbst wenn der Python-Code etwas komplexer sein wird als das entsprechende (und oft sehr knappe) Shell-Skript, ist es möglicherweise besser, die Shell zu entfernen und die Funktionalität durch native Python-Konstrukte zu ersetzen. Es ist oft eine gute Idee, die in einem externen Prozess geleistete Arbeit zu minimieren und die Kontrolle innerhalb Ihres eigenen Codes so weit wie möglich zu behalten, nur weil dies die Sichtbarkeit verbessert und das Risiko von gewünschten oder unerwünschten Nebenwirkungen verringert.
Platzhaltererweiterung, variable Interpolation und Umleitung lassen sich einfach durch native Python-Konstrukte ersetzen. Eine komplexe Shell-Pipeline, in der Teile oder alle in Python nicht angemessen umgeschrieben werden können, ist die einzige Situation, in der Sie möglicherweise die Verwendung der Shell in Betracht ziehen könnten. Sie sollten dennoch sicherstellen, dass Sie die Auswirkungen auf Leistung und Sicherheit verstehen.
Um dies zu vermeiden shell=True
, ersetzen Sie es einfach
subprocess.Popen("command -with -options 'like this' and\\ an\\ argument", shell=True)
mit
subprocess.Popen(['command', '-with','-options', 'like this', 'and an argument'])
Beachten Sie, dass das erste Argument eine Liste von Zeichenfolgen ist, an die übergeben werden soll execvp()
, und dass das Zitieren von Zeichenfolgen und Backslash-Escape-Shell-Metazeichen im Allgemeinen nicht erforderlich (oder nützlich oder korrekt) ist. Vielleicht sehen Sie auch Wann Sie Anführungszeichen um eine Shell-Variable setzen?
Abgesehen davon möchten Sie sehr oft vermeiden, Popen
dass einer der einfacheren Wrapper im subprocess
Paket das tut, was Sie wollen. Wenn Sie über genügend Python verfügen, sollten Sie es wahrscheinlich verwenden subprocess.run
.
- Damit
check=True
schlägt fehl, wenn der von Ihnen ausgeführte Befehl fehlgeschlagen ist.
- Damit
stdout=subprocess.PIPE
wird die Ausgabe des Befehls erfasst.
- Etwas dunkel,
universal_newlines=True
damit wird die Ausgabe in eine richtige Unicode-Zeichenfolge dekodiert (es ist nur bytes
in der Systemcodierung anders, unter Python 3).
Wenn nicht, möchten Sie für viele Aufgaben check_output
die Ausgabe von einem Befehl abrufen, während Sie überprüfen, ob er erfolgreich war, oder check_call
wenn keine Ausgabe zum Sammeln vorhanden ist.
Ich werde mit einem Zitat von David Korn schließen: "Es ist einfacher, eine tragbare Shell zu schreiben als ein tragbares Shell-Skript." Auch subprocess.run('echo "$HOME"', shell=True)
ist nicht auf Windows portierbar.
-l
an/bin/sh
(die Shell) anstelle desls
Programms unter Unix übergeben, wennshell=True
.shell=True
In den meisten Fällen sollte ein String-Argument anstelle einer Liste verwendet werden.