В Python, как я использую подпроцесс вместо os.system? - PullRequest
3 голосов
/ 07 января 2009

У меня есть сценарий Python, который вызывает исполняемую программу с различными аргументами (в данном примере это «sqlpubwiz.exe», то есть «Мастер публикации баз данных 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)

Этот код работает правильно, но я хотел бы привыкнуть к использованию подпроцесса , поскольку он предназначен для замены os.system. Однако после нескольких неудачных попыток я не могу заставить его работать должным образом.

Как будет выглядеть приведенный выше код, если он будет преобразован для использования подпроцесса вместо os.system?

Ответы [ 7 ]

5 голосов
/ 07 января 2009
import subprocess
p=subprocess.Popen(args, stdout=subprocess.PIPE)
print p.communicate()[0]

Это будет выглядеть примерно так же. Но путь не должен быть «каким бы ни был путь». Потому что это дает мне ошибку. Вы хотите "путь с побегом обратной косой черты" или "путь без побега".

Также аргументы должны иметь форму ['-arg', 'args'] вместо ['arg argsval'].

4 голосов
/ 07 января 2009

FYI, subprocess имеет функцию list2cmdline(), которая позволит вам увидеть строку, которую будет использовать Popen.

Ваша версия дает:

'"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'

с дополнительными кавычками около "-C server=myLocalServer;database=myLocalDatabase;trusted_connection=true" и "-targetserver 2000".

Правильно отформатирован:

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

дает:

'"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'

Кроме того, второстепенный вопрос, но это хорошая привычка - создавать последовательности, такие как args, которые не должны быть изменяемыми в кортежи вместо списков.

4 голосов
/ 07 января 2009

Ниже приведен мой пересмотренный код, основанный на Карлосе Рендоне носкло ), справке и предложениях:

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

(Примечание. Исходные значения аргументов, содержащие пробелы, необходимо преобразовать в отдельные элементы списка.)

4 голосов
/ 07 января 2009

Удалить кавычки из имени исполняемого файла. На первой строке вашего примера вместо

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

использование:

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

Это потому, что вам не нужно ничего избегать, потому что не будет задействована оболочка.

Тогда просто используйте subprocess.call(args) (не join аргументы, передайте их как список)

Если вы хотите захватить вывод (os.system не может этого сделать), просто следуйте подпроцессу документации:

result = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
print result
0 голосов
/ 07 января 2009

Команды Windows будут принимать прямую косую черту '/' вместо обратной косой черты в именах путей, поэтому вы можете использовать первую, чтобы избежать обратной косой черты в ваших командных строках. Не совсем ответ на ваш вопрос, но, возможно, полезно знать.

0 голосов
/ 07 января 2009

Это не ответ прямо на ваш вопрос, но я подумал, что это может быть полезно.

Если вам когда-либо понадобится более детальный контроль над тем, что возвращается для обработки исключений и т. Д., Вы также можете проверить pexpect . Я использовал его в ситуациях, когда вызываемый мной процесс не обязательно завершался с нормальными сигналами состояния или я хотел больше взаимодействовать с ним. Это довольно удобная функция.

0 голосов
/ 07 января 2009

Пожалуйста, помните, что os.system использует оболочку, и поэтому вы должны действительно передать

shell=True

конструктору / вызову Popen, чтобы эмулировать его должным образом. Конечно, вам может и не понадобиться оболочка, но она есть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...