Как в 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?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
0
9 607
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий
import subprocess
p=subprocess.Popen(args, stdout=subprocess.PIPE)
print p.communicate()[0]

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

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

Я пробовал это, но получаю следующую ошибку: WindowsError: [Error 3] Система не может найти указанный путь

Ray 07.01.2009 20:34

Я думаю, что Popen принимает аргументы как последовательность, а не большую строку, разделенную пробелами. Попробуйте просто передать args вместо cmd.

Jay Conrod 07.01.2009 20:45

Удаление кавычек позволило скрипту выполнить без ошибок, но файл sql не был создан. Как я могу увидеть консольный вывод exe?

Ray 07.01.2009 20:55

Теперь, когда я вижу ошибку sqlpubwiz exe. Он показывает:> Отсутствует / неверное количество аргументов. > Нераспознанный аргумент командной строки '-targetserver 2000' кстати, я использую список 'args', а не 'cmd'. Не знаете, почему sqlpubwiz не нравится, как аргументы передаются ему с помощью subprocess vs os.system?

Ray 07.01.2009 21:16

(Вот почему мне не очень повезло с подпроцессом, а не просто с использованием os.system)

Ray 07.01.2009 21:17

Бьюсь об заклад, ему нужны команды как ['-targetserver', '2000'], а не с пробелами.

Carlos Rendon 07.01.2009 21:45

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

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

Ray 07.01.2009 21:40

Должны ли значения args каким-то образом отличаться для подпроцесса, в отличие от того, как он создается в строковой команде для os.system?

Ray 07.01.2009 21:42

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

shell=True

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

Просто отвечу на вопрос :)

Ali Afshar 07.01.2009 21:14

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

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

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

# 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 принимают косую черту '/' вместо обратной косой черты в именах путей, поэтому вы можете использовать первую, чтобы избежать экранирования обратной косой черты в строках команд. Не совсем ответ на ваш вопрос, но, возможно, это полезно знать.

Другие вопросы по теме