En Python, ¿cómo uso el subproceso en lugar de os.system?

Tengo una secuencia de comandos de Python que llama a un progtwig ejecutable con varios argumentos (en este ejemplo, es ‘sqlpubwiz.exe’ que es el “Asistente de publicación de la base de datos de Microsoft SQL Server”):

import os sqlpubwiz = r'"C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe"' server = 'myLocalServer' database = 'myLocalDatabase' connection_values = ['server=' + server, 'database=' + database, 'trusted_connection=true'] connection_string = ';'.join(connection_values) dbms_version = '2000' sqlscript_filename = 'CreateSchema.sql' args = [ sqlpubwiz, 'script', '-C ' + connection_string, sqlscript_filename, '-schemaonly', '-targetserver ' + dbms_version, '-f', ] cmd = ' '.join(args) os.system(cmd) 

Este código se ejecuta correctamente, pero me gustaría acostumbrarme a utilizar el subproceso, ya que está destinado a reemplazar os.system. Sin embargo, después de algunos bashs fallidos, parece que no puedo hacerlo funcionar correctamente.

¿Cómo sería el código anterior si se convirtiera para usar un subproceso en lugar de os.system?

 import subprocess p=subprocess.Popen(args, stdout=subprocess.PIPE) print p.communicate()[0] 

Se vería más o menos igual. Pero el camino no debe ser r ‘”cualquiera que sea el camino”. Porque eso me da un error. Quieres “el camino con barras invertidas de escape” o r’el camino sin escapar ‘.

También args debe ser de la forma [‘-arg’, ‘args’] en lugar de [‘arg argsval’].

Eliminar comillas del nombre del ejecutable. En la primera línea de tu ejemplo, en lugar de

 sqlpubwiz = r'"C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe"' 

utilizar:

 sqlpubwiz = r'C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe' 

Eso es porque no tienes que escapar de nada ya que un shell no estará involucrado.

Luego simplemente use subprocess.call(args) (no se join los argumentos, páselos como una lista)

Si desea capturar la salida ( os.system no puede hacerlo) simplemente siga la documentación del subproceso :

 result = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0] print result 

A continuación se encuentra mi código revisado basado en la ayuda y sugerencias de Carlos Rendon (y nosklo ):

 # import os import subprocess sqlpubwiz = r'C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe' server = 'myLocalServer' database = 'myLocalDatabase' connection_values = ['server=' + server, 'database=' + database, 'trusted_connection=true'] connection_string = ';'.join(connection_values) dbms_version = '2000' sqlscript_filename = 'CreateSchema.sql' args = [ sqlpubwiz, 'script', '-C', connection_string, sqlscript_filename, '-schemaonly', '-targetserver', dbms_version, '-f', ] # cmd = ' '.join(args) # os.system(cmd) subprocess.call(args) 

(Nota: los valores de los argumentos originales que contenían espacios debían convertirse en elementos de lista separados).

Para su información, el subprocess tiene una función list2cmdline() que le permitirá ver la cadena que Popen utilizará.

Tu versión da:

 '"C:\\Program Files\\Microsoft SQL Server\\90\\Tools\\Publishing\\sqlpubwiz.exe" script "-C server=myLocalServer;database=myLocalDatabase;trusted_connection=true" CreateSchema.sql -schemaonly "-targetserver 2000" -f' 

con citas adicionales en torno a "-C server=myLocalServer;database=myLocalDatabase;trusted_connection=true" y "-targetserver 2000" .

Formato correcto:

 args = [ sqlpubwiz, 'script', '-C', connection_string, sqlscript_filename, '-schemaonly', '-targetserver', dbms_version, '-f', ] 

da:

 '"C:\\Program Files\\Microsoft SQL Server\\90\\Tools\\Publishing\\sqlpubwiz.exe" script -C server=myLocalServer;database=myLocalDatabase;trusted_connection=true CreateSchema.sql -schemaonly -targetserver 2000 -f' 

Además, es un punto secundario, pero es un buen hábito hacer secuencias como args que no necesitan ser mutables en tuplas en lugar de listas.

Esta no es una respuesta directamente a tu pregunta, pero pensé que podría ser útil.

En caso de que alguna vez desee un control más granular sobre lo que se devuelve para el manejo de excepciones, etc., también puede consultar pexpect . Lo he usado en situaciones en las que el proceso al que llamaba no necesariamente finalizaba con las señales de estado normales, o quería interactuar más con él. Es una función muy útil.

Los comandos de Windows aceptarán barras diagonales “/” en lugar de barras diagonales inversas en las rutas de acceso, por lo que puede usar el primero para evitar el escape de barras diagonales en las cadenas de comandos. No es exactamente una respuesta a su pregunta, pero tal vez sea útil saberla.

Por favor, recuerde que os.system usa el shell, por lo que realmente debe pasar

 shell=True 

al constructor de Popen / llamada para emularlo correctamente. Puede que no necesites una concha, por supuesto, pero ahí está.