Как использовать подпроцесс, когда несколько аргументов содержат пробелы?
Я работаю над оберткой script, которая будет выполнять исполняемый файл vmware, позволяя автоматизировать действия по запуску/завершению работы/регистрации/дешифрации виртуальной машины. Я пытаюсь использовать подпроцесс для обработки вызова исполняемого файла, но пробелы в пути исполняемых файлов и в параметрах исполняемого файла обрабатываются не подпроцессом. Ниже приведен фрагмент кода:
vmrun_cmd = r"c:/Program Files/VMware/VMware Server/vmware-cmd.bat"
def vm_start(target_vm):
list_arg = "start"
list_arg2 = "hard"
if vm_list(target_vm):
p = Popen([vmrun_cmd, target_vm, list_arg, list_arg2], stdout=PIPE).communicate()[0]
print p
else:
vm_register(target_vm)
vm_start(target_vm)
def vm_list2(target_vm):
list_arg = "-l"
p = Popen([vmrun_cmd, list_arg], stdout=PIPE).communicate()[0]
for line in p.split('\n'):
print line
Если я вызываю функцию vm_list2, я получаю следующий вывод:
$ ./vmware_control.py --list
C:\Virtual Machines\QAW2K3Server\Windows Server 2003 Standard Edition.vmx
C:\Virtual Machines\ubunturouter\Ubuntu.vmx
C:\Virtual Machines\vacc\vacc.vmx
C:\Virtual Machines\EdgeAS-4.4.x\Other Linux 2.4.x kernel.vmx
C:\Virtual Machines\UbuntuServer1\Ubuntu.vmx
C:\Virtual Machines\Other Linux 2.4.x kernel\Other Linux 2.4.x kernel.vmx
C:\Virtual Machines\QAClient\Windows XP Professional.vmx
Если я вызываю функцию vm_start, для которой требуется параметр path-to-vm, я получаю следующий вывод:
$ ./vmware_control.py --start "C:\Virtual Machines\ubunturouter\Ubuntu.vmx"
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.
По-видимому, наличие второго параметра со встроенными пространствами изменяет способ интерпретации первого параметра подпроцессом. Любые предложения по устранению этого?
python2.5.2/Cygwin/WinXP
Ответы
Ответ 1
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.
Чтобы получить это сообщение, вы либо:
-
Использование shell=True
:
vmrun_cmd = r"c:\Program Files\VMware\VMware Server\vmware-cmd.bat"
subprocess.Popen(vmrun_cmd, shell=True)
-
Изменение vmrun_cmd на другой части вашего кода
- Получение этой ошибки от чего-то внутри vmware-cmd.bat
Что нужно попробовать:
-
Откройте приглашение python, запустите следующую команду:
subprocess.Popen([r"c:\Program Files\VMware\VMware Server\vmware-cmd.bat"])
Если это сработает, то цитирование вопросов не может быть и речи. Если нет, вы выделили проблему.
Ответ 2
Если у вас есть пробелы в пути, самый простой способ, которым я нашел, чтобы они правильно интерпретировались, - это.
subprocess.call('""' + path + '""')
Я не знаю, почему именно ему нужны двойные двойные кавычки, но это то, что работает.
Ответ 3
В Python в MS Windows класс subprocess.Popen использует API CreateProcess для запуска процесса. CreateProcess принимает строку, а не нечто вроде массива аргументов. Python использует subprocess.list2cmdline для преобразования списка аргументов в строку для CreateProcess.
Если бы я был вами, я бы увидел, что возвращает subprocess.list2cmdline (args) (где args - первый аргумент Popen). Было бы интересно посмотреть, помещает ли он кавычки вокруг первого аргумента.
Конечно, это объяснение может не применяться в среде Cygwin.
Сказав все это, у меня нет MS Windows.
Ответ 4
Я считаю, что list2cmdline(), который выполняет обработку ваших аргументов в списке, разбивает любой аргумент string на пробелы, если строка не содержит двойные кавычки. Поэтому я ожидал бы
vmrun_cmd = r'"c:/Program Files/VMware/VMware Server/vmware-cmd.bat"'
чтобы быть тем, что вы хотите.
Вы также, вероятно, захотите окружить другие аргументы (например, target_vm
) в двойных кавычках, исходя из предположения, что они тоже представляют отдельный аргумент для представления в командной строке. Что-то вроде
r'"%s"' % target_vm
(например) должен соответствовать.
Смотрите документацию list2cmdline
Д А
Ответ 5
Одна из проблем заключается в том, что если команда окружена кавычками и не имеет пробелов, это может также запутать оболочку.
Итак, я делаю это:
if ' ' in raw_cmd:
fmt = '"%s"'
else:
fmt = '%s'
cmd = fmt % raw_cmd
Ответ 6
Это была довольно сложная проблема для последних трех наших... ничего не сказанное до сих пор работало, не используя r "или Popen со списком и так далее. В итоге работала комбинация строки формата и r" ". Поэтому мое решение таково:
subprocess.Popen("{0} -f {1}".format(pathToExe, r'"%s"' % pathToVideoFileOrDir))
где обе переменные pathToExe и pathToVideoFileOrDir имеют пробелы на своем пути. Использование\"в форматированной строке не работало и привело к той же ошибке, что первый путь не был обнаружен более корректно.
Ответ 7
2 вещи
1)
Вероятно, вы не хотите использовать трубку
Если выход подпрограммы больше 64 КБ, скорее всего, ваш процесс будет аварийно завершен.
http://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/
2)
Subprocess.Popen имеет оболочку аргументов ключевого слова, делая ее так, как будто оболочка анализировала ваши аргументы, установив shell = True, чтобы делать то, что вы хотите.
Ответ 8
Вот что мне не нравится
vmrun_cmd = r"c:/Program Files/VMware/VMware Server/vmware-cmd.bat"
У вас есть пробелы во имя самой команды, что затрудняет вашу оболочку. Следовательно, "c:\Program" не распознается как внутренняя или внешняя команда,
оперативная программа или командный файл. "
Вариант 1 - поместите ваш .BAT файл в другое место. Действительно, поместите все свои VMWare в другое место. Здесь правило: Не использовать каталог "Program Files" для всего. Это просто неправильно.
Вариант 2 - укажите значение vmrun_cmd
vmrun_cmd = r'"c:/Program Files/VMware/VMware Server/vmware-cmd.bat"'
Ответ 9
Почему вы используете r "? Я считаю, что если вы удалите" r" с самого начала, он будет рассматриваться как стандартная строка, которая может содержать пробелы. Затем Python должен правильно указывать строку при отправке ее в оболочку.
Ответ 10
Возможно, глупое предложение, но, возможно, попробуйте следующее: удалить подпроцесс + пробелы из уравнения:
import os
from subprocess Popen, PIPE
os.chdir(
os.path.join("C:", "Program Files", "VMware", "VMware Server")
)
p = Popen(
["vmware-cmd.bat", target_vm, list_arg, list_arg2],
stdout=PIPE
).communicate()[0]
Возможно, стоит попробовать.
p = Popen(
[os.path.join("C:", "Program Files", "VMware", "VMware Server", "vmware-cmd.bat"), ...