У меня есть сценарий 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?






import subprocess
p=subprocess.Popen(args, stdout=subprocess.PIPE)
print p.communicate()[0]
Это выглядело бы примерно так же. Но путь не должен быть «каким бы он ни был». Потому что это дает мне ошибку. Вам нужен «путь с экранированными обратными косыми чертами» или r «путь без экранирования».
Также аргументы должны иметь форму ['-arg', 'args'] вместо ['arg argsval'].
Я думаю, что Popen принимает аргументы как последовательность, а не большую строку, разделенную пробелами. Попробуйте просто передать args вместо cmd.
Удаление кавычек позволило скрипту выполнить без ошибок, но файл sql не был создан. Как я могу увидеть консольный вывод exe?
Теперь, когда я вижу ошибку sqlpubwiz exe. Он показывает:> Отсутствует / неверное количество аргументов. > Нераспознанный аргумент командной строки '-targetserver 2000' кстати, я использую список 'args', а не 'cmd'. Не знаете, почему sqlpubwiz не нравится, как аргументы передаются ему с помощью subprocess vs os.system?
(Вот почему мне не очень повезло с подпроцессом, а не просто с использованием os.system)
Бьюсь об заклад, ему нужны команды как ['-targetserver', '2000'], а не с пробелами.
Удалите кавычки из имени исполняемого файла. В первой строке вашего примера вместо
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
использование subprocess.call (args) дает мне ту же ошибку, что и Карлос Рендон:> Отсутствует / неверное количество аргументов. > Нераспознанный аргумент командной строки "-targetserver 2000".
Должны ли значения args каким-то образом отличаться для подпроцесса, в отличие от того, как он создается в строковой команде для os.system?
Помните, что os.system использует оболочку, поэтому вы действительно должны передать
shell=True
к конструктору / вызову Popen, чтобы правильно его эмулировать. Конечно, вам может и не понадобиться оболочка, но она есть.
Просто отвечу на вопрос :)
Это не ответ прямо на ваш вопрос, но я подумал, что это может быть полезно.
Если вам когда-нибудь понадобится более детальный контроль над тем, что возвращается для обработки исключений и т. д., Вы также можете проверить ожидание. Я использовал его в ситуациях, когда процесс, который я вызывал, не обязательно завершался с нормальными сигналами состояния, или я хотел больше с ним взаимодействовать. Это довольно удобная функция.
Ниже приведен мой исправленный код, основанный на помощи и предложениях Карлос Рендон (и носкло):
# 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)
(Примечание: исходные значения аргументов, содержащие пробелы, необходимо преобразовать в отдельные элементы списка.)
К вашему сведению, 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, которые не нужно преобразовывать в кортежи вместо списков.
Команды Windows принимают косую черту '/' вместо обратной косой черты в именах путей, поэтому вы можете использовать первую, чтобы избежать экранирования обратной косой черты в строках команд. Не совсем ответ на ваш вопрос, но, возможно, это полезно знать.
Я пробовал это, но получаю следующую ошибку: WindowsError: [Error 3] Система не может найти указанный путь