Ich rufe mit dem subprocess
Modul verschiedene Prozesse auf . Ich habe jedoch eine Frage.
In den folgenden Codes:
callProcess = subprocess.Popen(['ls', '-l'], shell=True)
und
callProcess = subprocess.Popen(['ls', '-l']) # without shell
Beide arbeiten. Nachdem ich die Dokumente gelesen hatte, wurde mir klar, dass dies shell=True
bedeutet, den Code über die Shell auszuführen. Das heißt, in Abwesenheit wird der Prozess direkt gestartet.
Was sollte ich für meinen Fall bevorzugen? Ich muss einen Prozess ausführen und seine Ausgabe erhalten. Welchen Vorteil habe ich, wenn ich es innerhalb oder außerhalb der Shell aufrufe.
python
subprocess
user225312
quelle
quelle
-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.shell=True
nachFalse
und umgekehrt ist ein Fehler. Aus den Dokumenten : "Unter POSIX mit shell = True (...) Wenn args eine Sequenz ist, gibt das erste Element die Befehlszeichenfolge an, und alle zusätzlichen Elemente werden als zusätzliche Argumente für die Shell selbst behandelt." Unter Windows gibt es eine automatische Konvertierung , die möglicherweise unerwünscht ist.Antworten:
Der Vorteil, nicht über die Shell aufzurufen, besteht darin, dass Sie kein "Mystery-Programm" aufrufen. Unter POSIX
SHELL
steuert die Umgebungsvariable, welche Binärdatei als "Shell" aufgerufen wird. Unter Windows gibt es keine Nachkommen der Bourne-Shell, sondern nur cmd.exe.Das Aufrufen der Shell ruft also ein Programm nach Wahl des Benutzers auf und ist plattformabhängig. Vermeiden Sie generell Aufrufe über die Shell.
Durch Aufrufen über die Shell können Sie Umgebungsvariablen und Dateiglob nach dem üblichen Mechanismus der Shell erweitern. Auf POSIX-Systemen erweitert die Shell Dateiglob zu einer Liste von Dateien. Unter Windows wird ein Dateiglob (z. B. "*. *") Von der Shell ohnehin nicht erweitert (Umgebungsvariablen in einer Befehlszeile werden jedoch um cmd.exe erweitert).
Wenn Sie der Meinung sind, dass Sie Erweiterungen von Umgebungsvariablen und Dateiglob möchten, untersuchen Sie die
ILS
Angriffe von 1992 auf Netzwerkdienste, die Unterprogrammaufrufe über die Shell ausgeführt haben. Beispiele sind die verschiedenensendmail
HintertürenILS
.Zusammenfassend verwenden
shell=False
.quelle
$SHELL
ist nicht korrekt. Um subprocess.html zu zitieren: "Unter Unix mitshell=True
ist die Shell standardmäßig/bin/sh
." (nicht$SHELL
)open
wenn Sie sichere Möglichkeiten zum Aufrufen eines Programms und zum Erfassen der Ausgabe wünschen.Quelle: Unterprozessmodul
quelle
Ein Beispiel, in dem mit Shell = True etwas schief gehen könnte, wird hier gezeigt
Überprüfen Sie das Dokument hier: subprocess.call ()
quelle
Das Ausführen von Programmen über die Shell bedeutet, dass alle an das Programm übergebenen Benutzereingaben gemäß der Syntax und den semantischen Regeln der aufgerufenen Shell interpretiert werden. Im besten Fall verursacht dies nur Unannehmlichkeiten für den Benutzer, da der Benutzer diese Regeln einhalten muss. Beispielsweise müssen Pfade mit speziellen Shell-Zeichen wie Anführungszeichen oder Leerzeichen maskiert werden. Im schlimmsten Fall führt dies zu Sicherheitslücken, da der Benutzer beliebige Programme ausführen kann.
shell=True
Manchmal ist es praktisch, bestimmte Shell-Funktionen wie Wortaufteilung oder Parametererweiterung zu verwenden. Wenn eine solche Funktion erforderlich ist, können Sie jedoch andere Module verwenden (z. B.os.path.expandvars()
zur Parametererweiterung odershlex
zur Wortaufteilung). Dies bedeutet mehr Arbeit, vermeidet jedoch andere Probleme.Kurzum: Auf
shell=True
jeden Fall vermeiden .quelle
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 einfachmit
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 imsubprocess
Paket das tut, was Sie wollen. Wenn Sie über genügend Python verfügen, sollten Sie es wahrscheinlich verwendensubprocess.run
.check=True
schlägt fehl, wenn der von Ihnen ausgeführte Befehl fehlgeschlagen ist.stdout=subprocess.PIPE
wird die Ausgabe des Befehls erfasst.universal_newlines=True
damit wird die Ausgabe in eine richtige Unicode-Zeichenfolge dekodiert (es ist nurbytes
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, odercheck_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.quelle
shell=True
, viele mit ausgezeichneten Antworten. Sie haben zufällig die ausgewählt, bei der es darum geht, warum .subprocess