How to use subprocess when multiple arguments cont

2019-02-16 08:08发布

I'm working on a wrapper script that will exercise a vmware executable, allowing for the automation of virtual machine startup/shutdown/register/deregister actions. I'm trying to use subprocess to handle invoking the executable, but the spaces in the executables path and in parameters of the executable are not being handled correctly by subprocess. Below is a code fragment:

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

If I call the vm_list2 function, I get the following output:

$ ./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

If I call the vm_start function, which requires a path-to-vm parameter, I get the following output:

$ ./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.

Apparently, the presence of a second parameter with embedded spaces is altering the way that subprocess is interpreting the first parameter. Any suggestions on how to resolve this?

python2.5.2/cygwin/winxp

10条回答
相关推荐>>
2楼-- · 2019-02-16 08:50

Here's what I don't like

vmrun_cmd = r"c:/Program Files/VMware/VMware Server/vmware-cmd.bat"

You've got spaces in the name of the command itself -- which is baffling your shell. Hence the "'c:\Program' is not recognized as an internal or external command, operable program or batch file."

Option 1 -- put your .BAT file somewhere else. Indeed, put all your VMWare somewhere else. Here's the rule: Do Not Use "Program Files" Directory For Anything. It's just wrong.

Option 2 -- quote the vmrun_cmd value

vmrun_cmd = r'"c:/Program Files/VMware/VMware Server/vmware-cmd.bat"'
查看更多
做个烂人
3楼-- · 2019-02-16 08:52

That was quite a hard problem for the last three ours....nothing stated so far did work, neither using r"" or Popen with a list and so on. What did work in the end was a combination of format string and r"". So my solution is this:

subprocess.Popen("{0} -f {1}".format(pathToExe, r'"%s"' % pathToVideoFileOrDir))

where both variables pathToExe and pathToVideoFileOrDir have whitespaces in their path. Using \" within the formatted string did not work and resulted in the same error that the first path is not detected any longer correctly.

查看更多
爷的心禁止访问
4楼-- · 2019-02-16 08:52

Why are you using r""? I believe that if you remove the "r" from the beginning, it will be treated as a standard string which may contain spaces. Python should then properly quote the string when sending it to the shell.

查看更多
甜甜的少女心
5楼-- · 2019-02-16 09:00

Possibly stupid suggestion, but perhaps try the following, to remove subprocess + spaces from the equation:

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]

It might also be worth trying..

p = Popen(
    [os.path.join("C:", "Program Files", "VMware", "VMware Server", "vmware-cmd.bat"), ...
查看更多
聊天终结者
6楼-- · 2019-02-16 09:01

2 things

1)

You probably don't want to use Pipe If the output of the subprogram is greater than 64KB it is likely your process will crash. http://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/

2) Subprocess.Popen has a keyword argument shell, making it as if the shell has been parsing your arguments, setting shell=True should do what you want.

查看更多
我想做一个坏孩纸
7楼-- · 2019-02-16 09:03

If you have spaces in the path, the easiest way I've found to get them interpreted properly is this.

subprocess.call('""' + path + '""')

I don't know why exactly it needs double double quotes, but that is what works.

查看更多
登录 后发表回答