subprocess.Popen
,实例化后运行该程序。然而,它不会等待它——它会在后台触发它,就像你输入了一样cmd &
在一个壳里。因此,在上面的代码中,您基本上定义了一个竞争条件 - 如果插入可以及时完成,它将显示正常,但如果不能,您会得到意外的输出。你没有等待你的第一次run()
'd PID 完成后,您只需返回它的Popen
实例并继续。
我不确定这种行为与文档有何矛盾,因为 Popen 上有一些非常明确的方法似乎表明不等待它,例如:
Popen.wait()
Wait for child process to terminate. Set and return returncode attribute.
不过,我确实同意该模块的文档可以改进。
要等待程序完成,我建议使用subprocess
的便捷方法,subprocess.call
,或使用communicate
on a Popen
对象(用于需要标准输出的情况)。您已经在第二次通话中执行此操作了。
### 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
此外,在大多数情况下,您不需要在 shell 中运行该命令。这是其中一种情况,但您必须像序列一样重写命令。这样做还可以让您避免传统的 shell 注入,并且不用担心引用,如下所示:
prog = ["mysql", "-u", "ve", "--execute", 'insert into foo values ("snargle", 2)']
subprocess.call(prog)
这甚至可以工作,并且不会像您期望的那样注入:
prog = ["printf", "%s", "<", "/etc/passwd"]
subprocess.call(prog)
以交互方式尝试一下。您可以避免 shell 注入的可能性,特别是在您接受用户输入时。我怀疑您正在使用不太令人敬畏的字符串方法与子进程通信,因为您在使序列正常工作时遇到了麻烦:^)