subprocess.Popen
, quando instanciado, executa o programa. No entanto, ele não espera por ele - ele o dispara em segundo plano como se você tivesse digitado cmd &
em uma concha. Portanto, no código acima, você definiu essencialmente uma condição de corrida - se as inserções puderem terminar a tempo, parecerá normal, mas se não, você obterá a saída inesperada. Você não está esperando por sua primeira run()
'd PID para terminar, você está simplesmente retornando seu Popen
instância e continuando. Não tenho certeza de como esse comportamento contradiz a documentação, porque existem alguns métodos muito claros no Popen que parecem indicar que não é esperado, como:
Popen.wait()
Wait for child process to terminate. Set and return returncode attribute.
Concordo, no entanto, que a documentação para este módulo poderia ser melhorada.
Para esperar que o programa termine, recomendo usar
subprocess
método de conveniência de, subprocess.call
, ou usando communicate
em um Popen
object (para o caso em que você precisa de stdout). Você já está fazendo isso para sua segunda chamada. ### 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
Além disso, na maioria dos casos, você não precisa executar o comando em um shell. Este é um desses casos, mas você terá que reescrever seu comando como uma sequência. Fazer dessa forma também permite que você evite a injeção de shell tradicional e se preocupe menos com citações, assim:
prog = ["mysql", "-u", "ve", "--execute", 'insert into foo values ("snargle", 2)']
subprocess.call(prog)
Isso até funcionará e não será injetado como você esperaria:
prog = ["printf", "%s", "<", "/etc/passwd"]
subprocess.call(prog)
Experimente interativamente. Você evita as possibilidades de injeção de shell, principalmente se estiver aceitando a entrada do usuário. Suspeito que você esteja usando o método de string menos incrível de comunicação com o subprocesso porque teve problemas para fazer as sequências funcionarem :^)