subprocess.Popen
, wenn es instanziiert wird, führt das Programm aus. Es wartet jedoch nicht darauf – es feuert es im Hintergrund ab, als ob Sie cmd &
eingegeben hätten in einer Schale. Im obigen Code haben Sie also im Wesentlichen eine Race-Bedingung definiert – wenn die Einfügungen rechtzeitig beendet werden können, erscheint es normal, aber wenn nicht, erhalten Sie die unerwartete Ausgabe. Sie warten nicht auf Ihren ersten run()
Wenn Sie die PID beenden möchten, geben Sie einfach ihr Popen
zurück Beispiel und weiter.
Ich bin mir nicht sicher, inwiefern dieses Verhalten der Dokumentation widerspricht, da es einige sehr klare Methoden auf Popen gibt, die anzuzeigen scheinen, dass nicht darauf gewartet wird, wie:
Popen.wait()
Wait for child process to terminate. Set and return returncode attribute.
Ich stimme jedoch zu, dass die Dokumentation für dieses Modul verbessert werden könnte.
Um auf das Ende des Programms zu warten, empfehle ich die Verwendung von subprocess
's Convenience-Methode subprocess.call
, oder mit communicate
auf einem Popen
Objekt (für den Fall, dass Sie stdout benötigen). Dies tun Sie bereits bei Ihrem zweiten Anruf.
### START MAIN
# copy some rows from a source table to a destination table
# note that the destination table is empty when this script is run
cmd = 'mysql -u ve --skip-column-names --batch --execute="insert into destination (select * from source limit 100000)" test'
subprocess.call(cmd)
# check to see how many rows exist in the destination table
cmd = 'mysql -u ve --skip-column-names --batch --execute="select count(*) from destination" test'
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
try: count = (int(process.communicate()[0][:-1]))
except: count = 0
Außerdem müssen Sie den Befehl in den meisten Fällen nicht in einer Shell ausführen. Dies ist einer dieser Fälle, aber Sie müssen Ihren Befehl wie eine Sequenz umschreiben. Auf diese Weise können Sie auch die traditionelle Shell-Injektion vermeiden und sich weniger Gedanken über das Zitieren machen, etwa so:
prog = ["mysql", "-u", "ve", "--execute", 'insert into foo values ("snargle", 2)']
subprocess.call(prog)
Dies wird sogar funktionieren und nicht so injizieren, wie Sie es erwarten würden:
prog = ["printf", "%s", "<", "/etc/passwd"]
subprocess.call(prog)
Probieren Sie es interaktiv aus. Sie vermeiden die Möglichkeiten der Shell-Injektion, insbesondere wenn Sie Benutzereingaben akzeptieren. Ich vermute, Sie verwenden die weniger großartige String-Methode zur Kommunikation mit Subprozessen, weil Sie Probleme hatten, die Sequenzen zum Laufen zu bringen :^)