subprocess.Popen
, cuando se crea una instancia, ejecuta el programa. Sin embargo, no lo espera, lo dispara en segundo plano como si hubiera escrito cmd &
en una concha Entonces, en el código anterior, esencialmente ha definido una condición de carrera:si las inserciones pueden terminar a tiempo, parecerá normal, pero si no, obtendrá un resultado inesperado. No estás esperando tu primera run()
'd PID para terminar, simplemente está devolviendo su Popen
instancia y continuando.
No estoy seguro de cómo este comportamiento contradice la documentación, porque hay algunos métodos muy claros en Popen que parecen indicar que no se espera, como:
Popen.wait()
Wait for child process to terminate. Set and return returncode attribute.
Sin embargo, estoy de acuerdo en que la documentación de este módulo podría mejorarse.
Para esperar a que termine el programa, recomiendo usar subprocess
método de conveniencia, subprocess.call
, o usando communicate
en un Popen
object (para el caso en que necesite stdout). Ya está haciendo esto para su segunda llamada.
### 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
Además, en la mayoría de los casos, no necesita ejecutar el comando en un shell. Este es uno de esos casos, pero tendrá que volver a escribir su comando como una secuencia. Hacerlo de esa manera también le permite evitar la inyección de shell tradicional y preocuparse menos por citar, así:
prog = ["mysql", "-u", "ve", "--execute", 'insert into foo values ("snargle", 2)']
subprocess.call(prog)
Esto incluso funcionará y no se inyectará como cabría esperar:
prog = ["printf", "%s", "<", "/etc/passwd"]
subprocess.call(prog)
Pruébelo de forma interactiva. Evita las posibilidades de la inyección de shell, especialmente si está aceptando la entrada del usuario. Sospecho que está utilizando el método de cadena menos impresionante para comunicarse con el subproceso porque tuvo problemas para que las secuencias funcionaran :^)