subprocess.Popen
, wanneer geïnstantieerd, voert het programma uit. Het wacht er echter niet op -- het activeert het op de achtergrond alsof je cmd &
typt in een schelp. Dus in de bovenstaande code heb je in wezen een raceconditie gedefinieerd - als de inserts op tijd klaar zijn, lijkt het normaal, maar als dat niet het geval is, krijg je de onverwachte output. Je wacht niet op je eerste run()
'd PID om te voltooien, je retourneert gewoon de Popen
instantie en doorgaan.
Ik weet niet zeker hoe dit gedrag in tegenspraak is met de documentatie, want er zijn enkele zeer duidelijke methoden op Popen die lijken aan te geven dat er niet op wordt gewacht, zoals:
Popen.wait()
Wait for child process to terminate. Set and return returncode attribute.
Ik ben het er echter mee eens dat de documentatie voor deze module kan worden verbeterd.
Om te wachten tot het programma klaar is, raad ik aan om subprocess
te gebruiken 's gemaksmethode, subprocess.call
, of gebruik communicate
op een Popen
object (voor het geval je stdout nodig hebt). U doet dit al voor uw tweede gesprek.
### 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
Bovendien hoeft u de opdracht in de meeste gevallen niet in een shell uit te voeren. Dit is een van die gevallen, maar u moet uw opdracht als een reeks herschrijven. Door het op die manier te doen, kun je ook traditionele shell-injectie vermijden en je minder zorgen maken over citeren, zoals:
prog = ["mysql", "-u", "ve", "--execute", 'insert into foo values ("snargle", 2)']
subprocess.call(prog)
Dit zal zelfs werken en zal niet injecteren zoals je zou verwachten:
prog = ["printf", "%s", "<", "/etc/passwd"]
subprocess.call(prog)
Probeer het interactief. U vermijdt de mogelijkheden van shell-injectie, vooral als u gebruikersinvoer accepteert. Ik vermoed dat je de minder geweldige tekenreeksmethode gebruikt om met het subproces te communiceren, omdat je problemen had om de reeksen te laten werken :^)