Mysql
 sql >> Database >  >> RDS >> Mysql

Perché subprocess.Popen non attende fino al termine del processo figlio?

subprocess.Popen , quando istanziato, esegue il programma. Tuttavia, non lo aspetta:si spegne in background come se avessi digitato cmd & in una conchiglia. Quindi, nel codice sopra, hai essenzialmente definito una condizione di gara:se gli inserti possono finire in tempo, sembrerà normale, ma in caso contrario otterrai un output imprevisto. Non stai aspettando il tuo primo run() 'd PID per finire, stai semplicemente restituendo il suo Popen istanza e continuando.

Non sono sicuro di come questo comportamento contraddica la documentazione, perché ci sono alcuni metodi molto chiari su Popen che sembrano indicare che non è stato atteso, come:

Popen.wait()
  Wait for child process to terminate. Set and return returncode attribute.

Sono d'accordo, tuttavia, che la documentazione per questo modulo potrebbe essere migliorata.

Per attendere il completamento del programma, ti consiglio di utilizzare subprocess metodo di convenienza di , subprocess.call o utilizzando communicate su un Popen oggetto (per il caso in cui hai bisogno di stdout). Lo stai già facendo per la tua seconda chiamata.

### 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

Inoltre, nella maggior parte dei casi, non è necessario eseguire il comando in una shell. Questo è uno di quei casi, ma dovrai riscrivere il tuo comando come una sequenza. In questo modo puoi anche evitare l'iniezione di shell tradizionale e preoccuparti meno delle quotazioni, in questo modo:

prog = ["mysql", "-u", "ve", "--execute", 'insert into foo values ("snargle", 2)']
subprocess.call(prog)

Funzionerà anche e non si inietterà come ti aspetteresti:

prog = ["printf", "%s", "<", "/etc/passwd"]
subprocess.call(prog)

Provalo in modo interattivo. Eviti le possibilità dell'iniezione di shell, in particolare se stai accettando l'input dell'utente. Sospetto che tu stia usando il metodo di stringa meno eccezionale per comunicare con il sottoprocesso perché hai avuto problemi a far funzionare le sequenze :^)