2009-04-30 3 views
16

Sto lavorando a uno script wrapper che eseguirà un eseguibile vmware, consentendo l'automazione delle operazioni di avvio/arresto/registrazione/annullamento della macchina virtuale. Sto cercando di utilizzare il sottoprocesso per gestire il richiamo dell'eseguibile, ma gli spazi nel percorso degli eseguibili e nei parametri dell'eseguibile non vengono gestiti correttamente dal sottoprocesso. Ecco un frammento di codice:Come utilizzare il sottoprocesso quando più argomenti contengono spazi?

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 

Se chiamo la funzione vm_list2, ottengo il seguente 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 

Se chiamo la funzione vm_start, che richiede un parametro path-to-vm, ottengo il seguente 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. 

a quanto pare, la presenza di un secondo parametro con spazi incorporati sta modificando il modo in cui sottoprocesso interpreta il primo parametro. Qualche suggerimento su come risolvere questo?

python2.5.2/Cygwin/WinXP

+0

Perché le tue barre sono in c:/Programmi/VMware/VMware Server/vmware-cmd. bat sta andando nella direzione sbagliata? Non è c: \ Program Files \ ...? –

+2

Beh, cygwin è * nix port, quindi sembra che lo standard (o quello che ho capito sia lo standard) * nix slash notation La mia comprensione è che il sottoprocesso dovrebbe tradurre il separatore in qualsiasi cosa il sistema sottostante abbia bisogno: –

+0

ha risolto per ora? – Gohan

risposta

-2

Perché stai usando r ""? Credo che se si rimuove la "r" dall'inizio, verrà trattata come una stringa standard che potrebbe contenere spazi. Python dovrebbe quindi citare correttamente la stringa quando la invia alla shell.

+0

Ho controllato questo, e lo stato della stringa non cambia il comportamento –

+2

Ha senso usare r " ... \ ... "per i nomi di file di Windows –

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

Per ottenere questo messaggio, o si è:

  1. Utilizzando shell=True:

    vmrun_cmd = r"c:\Program Files\VMware\VMware Server\vmware-cmd.bat" 
    subprocess.Popen(vmrun_cmd, shell=True) 
    
  2. Modifica vmrun_cmd in altra parte del codice di

  3. Ottenere questo errore qualcosa dentro vmware-cmd.bat

cose da provare:

  • Aprire un prompt di pitone, eseguire il seguente comando:

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

Se funziona, le questioni poi citando sono fuori questione. In caso contrario, hai risolto il problema.

+0

In ordine: 1: Sono rimasto esplicitamente lontano dall'impostazione di shell = True, in modo che non è vero? 2: vmrun_cmd è una costante globale utilizzata esattamente nello stesso modo ogni volta. 3: No. L'eseguibile non è stato invocato dal momento in cui si verifica l'errore - questo è l'inizio della stringa che specifica il suo percorso. –

+0

@Rob Carr: modificato la mia risposta, prova il codice sopra – nosklo

1

Credo che list2cmdline(), che sta eseguendo l'elaborazione del proprio elenco args, divida qualsiasi argomento stringa su spazi vuoti a meno che la stringa contenga doppie virgolette. Quindi mi aspetterei

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

di essere ciò che si desidera.

Probabilmente vorrai circondare anche gli altri argomenti (come target_vm) tra virgolette sul presupposto che anch'essi rappresentino ciascuno un argomento distinto da presentare alla riga di comando. Qualcosa di simile

r'"%s"' % target_vm 

(per esempio) dovrebbe soddisfare.

Vedi the list2cmdline documentation

D'A

+0

Bene, target_vm è un argomento, piuttosto che una costante, quindi qual è il metodo migliore per la doppia quotazione in quella situazione? –

+0

Probabilmente lo chiamerei come r ""% s "'% target_vm – darch

+0

Man, è difficile da leggere nel commento. Spostandolo alla risposta. – darch

-2

Forse stupido suggerimento, ma forse provare la seguente, per rimuovere il sottoprocesso + spazi con l'equazione:

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] 

Potrebbe anche essere la pena di provare.

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

In Python su MS Windows, la subp La classe rocess.Popen utilizza l'API CreateProcess per avviare il processo. CreateProcess prende una stringa piuttosto che qualcosa come una matrice di argomenti. Python utilizza subprocess.list2cmdline per convertire l'elenco di argomenti in una stringa per CreateProcess.

Se fossi in te, vedrei cosa restituisce subprocess.list2cmdline (args) (dove args è il primo argomento di Popen). Sarebbe interessante vedere se sta mettendo le virgolette attorno al primo argomento.

Naturalmente questa spiegazione potrebbe non essere applicabile in un ambiente Cygwin.

Detto questo, non ho MS Windows.

-1

Ecco quello che non mi piace spazi

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

hai nel nome del comando stesso - che è sconcertante la shell. Quindi "c: \ Program" non è riconosciuto come comando interno o esterno, il programma operativo o il file batch ".

Opzione 1: inserisci il tuo file .BAT da un'altra parte. Effettivamente, metti tutto il tuo VMWare da qualche altra parte. Ecco la regola: Non utilizzare la directory "Programmi" per nulla. È semplicemente sbagliato.

Opzione 2 - citare il valore vmrun_cmd

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

Se si dispone di spazi nel percorso, il modo più semplice che ho trovato per farli interpretati correttamente è questo.

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

Non so perché esattamente occorrono doppi apici, ma questo è ciò che funziona.

0

Un problema è che se il comando è circondato da virgolette e non ha spazi, ciò potrebbe anche confondere la shell.

Così faccio questo:

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

cmd = fmt % raw_cmd 
0

Quello era un bel problema difficile per gli ultimi tre nostri .... niente dichiarato il lavoro finora fatto, né utilizzando R "" o Popen con una lista e così sopra. Alla fine, ciò che ha funzionato è stata una combinazione di format string e r "". Quindi la mia soluzione è questa:

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

in cui entrambe le variabili PathToExe e pathToVideoFileOrDir hanno spazi bianchi nel loro percorso. L'utilizzo di \ "all'interno della stringa formattata non ha funzionato e ha provocato lo stesso errore che il primo percorso non è stato rilevato correttamente.