Как в Python использовать подпроцесс вместо os.system?

У меня есть скрипт 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?


person Ray    schedule 07.01.2009    source источник


Ответы (7)


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

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

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

person Carlos Rendon    schedule 07.01.2009
comment
Я пробовал это, но получаю следующую ошибку: WindowsError: [Ошибка 3] Система не может найти указанный путь - person Ray; 07.01.2009
comment
Я думаю, что Popen принимает аргументы как последовательность, а не как большую строку, разделенную пробелами. Попробуйте просто передать «args» вместо «cmd». - person Jay Conrod; 07.01.2009
comment
Удаление кавычек позволило выполнить скрипт без ошибок, но файл sql не был создан. Как я могу увидеть консольный вывод exe? - person Ray; 07.01.2009
comment
Теперь, когда я вижу ошибку от sqlpubwiz exe. Он показывает: ›Отсутствует/неправильное количество аргументов. ›Неопознанный аргумент командной строки '-targetserver 2000', кстати, я использую список 'args', а не 'cmd'. Не знаете, почему sqlpubwiz не нравится, как ему передаются аргументы с использованием подпроцесса и os.system? - person Ray; 07.01.2009
comment
(Вот почему мне не очень повезло с подпроцессом по сравнению с использованием только os.system) - person Ray; 07.01.2009
comment
Бьюсь об заклад, он хочет, чтобы команды были как ['-targetserver', '2000'], а не с пробелами. - person Carlos Rendon; 07.01.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
person nosklo    schedule 07.01.2009
comment
использование subprocess.call(args) дает мне ту же ошибку, что и Карлос Рендон: ›Отсутствует/неверное количество аргументов. ›Нераспознанный аргумент командной строки «-targetserver 2000». - person Ray; 07.01.2009
comment
Должны ли значения аргументов каким-то образом отличаться для подпроцесса, в отличие от того, как они создаются в строковой команде для os.system? - person Ray; 07.01.2009

Ниже приведен мой пересмотренный код, основанный на Carlos Рендон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)

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

person Ray    schedule 07.01.2009

К вашему сведению, 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, которые не нужно изменять в кортежи, а не в списки.

person pantsgolem    schedule 07.01.2009

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

shell=True

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

person Ali Afshar    schedule 07.01.2009
comment
Просто отвечаю на вопрос :) - person Ali Afshar; 07.01.2009

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

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

person Scanningcrew    schedule 07.01.2009

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

person Jeff Bauer    schedule 07.01.2009