2009-04-30 13 views
16

Tôi đang làm việc trên một kịch bản trình bao bọc sẽ thực thi một vmware thực thi, cho phép tự động hóa các hoạt động khởi động/tắt máy/đăng ký/hủy đăng ký máy ảo. Tôi đang cố gắng sử dụng subprocess để xử lý gọi thực thi, nhưng không gian trong đường dẫn thực thi và trong các tham số của thực thi không được xử lý một cách chính xác bởi subprocess. Dưới đây là một đoạn mã:Cách sử dụng tiến trình con khi nhiều đối số chứa dấu cách?

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 

Nếu tôi gọi hàm vm_list2, tôi nhận được kết quả như sau:

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

Nếu tôi gọi hàm vm_start, đòi hỏi một tham số path-to-vm, Tôi nhận được kết quả sau:

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

Rõ ràng, sự hiện diện của tham số thứ hai với không gian được nhúng làm thay đổi cách mà quy trình con giải thích tham số đầu tiên. Bất kỳ đề xuất nào về cách giải quyết vấn đề này?

python2.5.2/cygwin/winxp

+0

Tại sao các dấu gạch chéo của bạn trong c:/Program Files/VMware/VMware Server/vmware-cmd. bat đi sai đường? Không phải là c: \ Program Files \ ...? –

+2

Vâng, Cygwin là cổng * nix, vì vậy nó có vẻ giống như tiêu chuẩn (hoặc những gì tôi hiểu là tiêu chuẩn) * nix slash ký hiệu Sự hiểu biết của tôi là tiến trình con nên dịch bộ phân tách thành bất kỳ hệ thống nào cần thiết. –

+0

đã giải quyết ngay bây giờ chưa? – Gohan

Trả lời

-2

Tại sao bạn sử dụng r ""? Tôi tin rằng nếu bạn loại bỏ "r" ngay từ đầu, nó sẽ được coi là một chuỗi chuẩn có thể chứa khoảng trắng. Sau đó Python sẽ trích dẫn đúng chuỗi khi gửi nó đến trình bao.

+0

Tôi đã kiểm tra điều này và trạng thái chuỗi thô không thay đổi hành vi. –

+2

Làm cho tinh thần sử dụng r " ... \ ... "cho tên tệp Windows. –

4
'c:\Program' is not recognized as an internal or external command, 
operable program or batch file. 

Để nhận được thông báo này, bạn là một trong hai:

  1. Sử dụng shell=True:

    vmrun_cmd = r"c:\Program Files\VMware\VMware Server\vmware-cmd.bat" 
    subprocess.Popen(vmrun_cmd, shell=True) 
    
  2. Thay đổi vmrun_cmd trên một phần khác của mã của bạn

  3. Bắt lỗi này từ một cái gì đó bên trong vmware-cmd.bat

Những điều cần thử:

  • mở một dấu nhắc python, chạy lệnh sau:

    subprocess.Popen([r"c:\Program Files\VMware\VMware Server\vmware-cmd.bat"]) 
    

Nếu thành công, các vấn đề sau đó trích dẫn là ra câu hỏi. Nếu không, bạn đã bị cô lập vấn đề.

+0

Theo thứ tự: 1: Tôi rõ ràng tránh xa việc đặt shell = True, do đó phải không. 2: vmrun_cmd là hằng số toàn cầu được sử dụng chính xác theo cùng một cách mỗi lần. 3: Không. Tệp thi hành đã không được gọi bởi thời gian xảy ra lỗi - đó là sự khởi đầu của chuỗi chỉ định đường dẫn của nó. –

+0

@Rob Carr: chỉnh sửa câu trả lời của tôi, hãy thử mã trên – nosklo

-1

2 điều

1)

Bạn có lẽ không muốn sử dụng ống Nếu đầu ra của chương trình con là lớn hơn 64KB nó có khả năng xử lý của bạn sẽ sụp đổ. http://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/

2) Subprocess.Popen có đối số từ khóa shell, làm cho shell như phân tích cú pháp đối số của bạn, đặt shell = True sẽ làm những gì bạn muốn.

1

Tôi tin rằng list2cmdline(), đang thực hiện xử lý danh sách của bạn, tách bất kỳ chuỗi arg nào trên khoảng trắng trừ khi chuỗi chứa dấu ngoặc kép. Vì vậy, tôi mong đợi

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

là những gì bạn muốn.

Bạn cũng có thể muốn bao quanh các đối số khác (như target_vm) trong dấu ngoặc kép trên giả thiết rằng chúng cũng đại diện cho một arg riêng biệt để trình bày cho dòng lệnh. Một cái gì đó như

r'"%s"' % target_vm 

(ví dụ) phải phù hợp.

Xem the list2cmdline documentation

D'Một

+0

Vâng, target_vm là một sự tranh luận, chứ không phải là một hằng số, vậy phương pháp nào tốt nhất cho việc trích dẫn kép trong tình huống đó? –

+0

Tôi có thể cụm từ nó là r '"% s"'% target_vm – darch

+0

Con người, thật khó đọc trong nhận xét. Di chuyển nó đến câu trả lời. – darch

-2

gợi ý Có thể ngu ngốc, nhưng có lẽ thử những điều sau đây, để loại bỏ tiến trình con + không gian từ phương trình:

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] 

Nó cũng có thể là đáng tham khảo. .

p = Popen(
    [os.path.join("C:", "Program Files", "VMware", "VMware Server", "vmware-cmd.bat"), ... 
2

Trong Python trên MS Windows, subp rocess.Popen class sử dụng API CreateProcess để bắt đầu quá trình. CreateProcess lấy một chuỗi thay vì một cái gì đó giống như một mảng các đối số. Python sử dụng subprocess.list2cmdline để chuyển đổi danh sách các arg thành một chuỗi cho CreateProcess.

Nếu tôi là bạn, tôi sẽ thấy những gì subprocess.list2cmdline (args) trả về (trong đó arg là đối số đầu tiên của Popen). Nó sẽ là thú vị để xem nếu nó được đặt dấu ngoặc kép xung quanh đối số đầu tiên.

Tất nhiên, giải thích này có thể không áp dụng trong môi trường Cygwin.

Có nói tất cả điều này, tôi không có MS Windows.

-1

Đây là những gì tôi không thích không gian

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

Bạn đã có trong tên của lệnh riêng của mình - đó là baffling shell của bạn. Do đó, '' c: \ Program 'không được nhận dạng như một lệnh nội bộ hoặc bên ngoài, chương trình hoặc tập tin thực thi. "

Tùy chọn 1 - đặt tệp .BAT của bạn ở một nơi khác. Thật vậy, đặt tất cả VMWare của bạn ở một nơi khác. Đây là quy tắc: Không sử dụng thư mục "Program Files" cho bất kỳ điều gì. Nó chỉ là sai.

Lựa chọn 2 - trích giá trị vmrun_cmd

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

Nếu bạn có các khoảng trống trong đường dẫn, cách dễ nhất tôi đã tìm thấy để có được chúng giải thích đúng là thế này.

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

Tôi không biết tại sao chính xác nó cần gấp đôi dấu ngoặc kép, nhưng đó là những gì hiệu quả.

0

Một vấn đề là nếu lệnh được bao quanh với dấu ngoặc kép và không có dấu cách, điều đó cũng có thể gây nhầm lẫn cho trình bao.

Vì vậy, tôi làm điều này:

if ' ' in raw_cmd: 
    fmt = '"%s"' 
else: 
    fmt = '%s' 

cmd = fmt % raw_cmd 
0

Đó là một vấn đề khá khó khăn cho ba của chúng ta cuối cùng .... không có gì nói cho đến nay đã làm việc, không phải sử dụng r "" hoặc Popen với một danh sách và do đó trên. Những gì đã làm việc cuối cùng là một sự kết hợp của chuỗi định dạng và r "". Vì vậy, giải pháp của tôi là:

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

trong đó cả hai biến pathToExe và pathToVideoFileOrDir đều có khoảng trắng trong đường dẫn của chúng. Sử dụng \ "trong chuỗi định dạng không hoạt động và dẫn đến cùng một lỗi mà đường dẫn đầu tiên không được phát hiện chính xác nữa.

Các vấn đề liên quan