Warum Teilprozess.Popen() mit shell=True anders funktionieren auf Linux vs Windows?
Bei der Verwendung subprocess.Popen(args, shell=True)
zu laufen "gcc --version
" (nur als Beispiel), auf Windows bekommen wir dies:
>>> from subprocess import Popen
>>> Popen(['gcc', '--version'], shell=True)
gcc (GCC) 3.4.5 (mingw-vista special r3) ...
Damit es ordentlich Druck aus der Fassung, als ich erwarte. Aber auf Linux bekommen wir dies:
>>> from subprocess import Popen
>>> Popen(['gcc', '--version'], shell=True)
gcc: no input files
Weil gcc noch nicht erhielt die --version
option.
Den docs nicht genau angeben, was geschehen soll, um die Argumente unter Windows ist, aber er sagt, auf Unix, "Wenn args ist eine Sequenz, das erste Element gibt den Befehl, und alle weiteren Elemente werden so behandelt, als zusätzliche shell-Argumente". IMHO der Windows-Weg ist besser, weil es erlaubt, Sie zu behandeln Popen(arglist)
ruft die gleiche wie Popen(arglist, shell=True)
lieben.
Warum der Unterschied zwischen Windows und Linux hier?
InformationsquelleAutor Ben Hoyt | 2009-08-10
Du musst angemeldet sein, um einen Kommentar abzugeben.
Eigentlich auf Windows, es wird
cmd.exe
wennshell=True
- es stelltcmd.exe /c
(es sieht tatsächlich dieCOMSPEC
Umgebungsvariable lautet jedochcmd.exe
wenn nicht vorhanden), um die shell-Argumente. (Auf Windows 95/98 verwendet die intermediatew9xpopen
Programm tatsächlich zu starten den Befehl).Also die seltsame Umsetzung ist eigentlich der
UNIX
eine, die nicht die folgenden (wobei jeder Raum trennt ein anderes argument):Sieht es aus wie die richtige Umsetzung (zumindest auf Linux) wäre:
Da dies würde den Kommando-string aus den genannten Parametern, und geben Sie die anderen Parameter erfolgreich.
Aus der
sh
Mann Seite Abschnitt für-c
:Dieser patch scheint ziemlich einfach zu tun der trick:
Hinzugefügt bugs.python.org/issue6689 - wäre gut, wenn Sie ihm Folgen könnte, Kommentar etc
Danke! Ich habe mich auf die nosy-Liste.
Für Referenz, der patch wurde abgelehnt. Es kann eine gute Idee sein, zu betrachten, ob die Dokumentation muss geändert werden, statt - ich werde verlassen, dass bis zu einer interessierten Partei
InformationsquelleAutor David Fraser
Aus der subprocess.py Quelle:
Nicht beantworten, warum gerade verdeutlicht, dass Sie sehen, das erwartete Verhalten.
Dem "warum" ist wohl, dass es auf UNIX-artigen Systemen, die Argumente sind eigentlich Durchlaufen, um Anwendungen (mit der
exec*
Familie von anrufen) wie ein array von strings. In anderen Worten, der aufrufende Prozess entscheidet, was in die command line argument. In der Erwägung, dass, wenn man es mit einem shell der aufrufende Prozess eigentlich nur die chance erhält, einen einzigen Befehl für die Kommandozeile an die shell zur Ausführung: Der gesamte Befehl, der ausgeführt werden soll, ausführbaren Namen und Argumente, wie eine einzige Zeichenkette.Aber auf Windows, die gesamte Befehl-Linie (gemäß der oben genannten Dokumentation) übergeben wird, als eine einzelne Zeichenfolge an den Kind-Prozess. Wenn man sich die CreateProcess API-Dokumentation, Sie werden feststellen, dass es erwartet, dass alle in der Befehlszeile-Argumente werden verkettet, der in eine große Zeichenfolge (daher der Aufruf zu
list2cmdline
).Plus ist die Tatsache, dass auf UNIX-artigen Systemen gibt es eigentlich ist eine shell, die können Sie nützliche Dinge tun, so vermute ich, dass der andere Grund für den Unterschied ist, dass auf Windows
shell=True
tut nichts, das ist, warum es ist so zu arbeiten, wie Sie sehen. Der einzige Weg, um die beiden Systeme handeln identisch wäre es zu einfach, alle Kommandozeilen-Argumente, wennshell=True
auf Windows.cmd.exe
), aber der Kommentar, den du oben zitiert zeigt an, dass Python nicht wirklich zu nutzen, wenn die shell=True (stattdessen verwendet esCreateProcess()
direkt).Danke -- wie Greg erwähnt, es ist definitiv eine shell auf einem Windows - (cmd.exe oder das man in COMSPEC). Und es wird von Popen (obwohl über CreateProcess) - siehe subprocess.py Quelle. So ist es immer noch auf jeden Fall scheint mir, dass der Teilprozess sollte Sie funktionieren auf die gleiche Weise, um zu vermeiden, Portabilität Fallstricke...
Hinweis: die Dokumentation wurde aktualisiert, seit 2010
InformationsquelleAutor Adam Batkin
Den Grund für die UNIX-Verhalten von
shell=True
ist zu tun, zitiert. Wenn wir schreiben Sie ein shell-Befehl, es wird split bei Leerzeichen, so müssen wir zitieren, einige Argumente:Dies führt zu Problemen, wenn unsere Argumente enthalten Zitate, die erfordert, Flucht:
Manchmal bekommen wir schrecklichen Situationen wo
\
geschützt werden müssen, auch!Natürlich, das eigentliche problem ist, dass wir versuchen zu nutzen eine string angeben mehrere strings. Beim aufrufen von system-Befehle, die meisten Programmiersprachen vermeiden Sie dies, indem Sie uns zu schicken, die mehrere Zeichenfolgen in den ersten Platz, daher:
Manchmal kann es nett sein, zu laufen "raw" - shell-Kommandos; zum Beispiel, wenn wir die kopieren-einfügen etwas von einem shell-Skript oder eine Website, und wir wollen nicht zu konvertieren alle von der schrecklichen Flucht manuell. Das ist, warum die
shell=True
option vorhanden ist:Ich bin nicht vertraut mit Windows, also ich weiß nicht, wie oder warum verhält es sich anders.
InformationsquelleAutor Warbo