2009-04-30 12 views
16

Estoy trabajando en una secuencia de comandos envoltura que ejercerá un ejecutable vmware, lo que permite la automatización de las acciones de inicio/cierre/registro/anulación de la máquina virtual. Estoy tratando de usar un subproceso para manejar la invocación del ejecutable, pero los espacios en la ruta de los ejecutables y en los parámetros del ejecutable no se manejan correctamente por subproceso. A continuación se muestra un fragmento de código:Cómo usar el subproceso cuando varios argumentos contienen espacios?

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 

Si llamo a la función vm_list2, me sale el siguiente resultado:

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

Si llamo a la función vm_start, lo que requiere un parámetro de ruta-a vm, me sale el siguiente resultado:

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

al parecer, la presencia de un segundo parámetro con espacios incrustados está alterando la forma en que el subproceso está interpretando el primer parámetro. ¿Algunas sugerencias para resolver esto?

python2.5.2/cygwin/WinXP

+0

¿Por qué son sus barras oblicuas en c:/Archivos de programa/VMware/VMware Server/vmware-cmd. ¿va mal por error? ¿No es c: \ Archivos de programa \ ...? –

+2

Bueno, cygwin es el puerto * nix, por lo que parece gustarle el estándar (o lo que entiendo que es el estándar) * notación de barras de nix Tengo entendido que el subproceso debe traducir el separador a lo que necesite el sistema subyacente. –

+0

¿Lo resolvió por ahora? – Gohan

Respuesta

-2

¿Por qué utiliza r ""? Creo que si elimina la "r" desde el principio, se tratará como una cadena estándar que puede contener espacios. Python debería citar correctamente la cadena cuando la envía al shell.

+0

Lo he comprobado y el estado de la cadena sin formato no cambia el comportamiento. –

+2

Tiene sentido usar r " ... \ ... "para nombres de archivos de Windows. –

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

Para recibir este mensaje, usted es ya sea:

  1. Usando shell=True:

    vmrun_cmd = r"c:\Program Files\VMware\VMware Server\vmware-cmd.bat" 
    subprocess.Popen(vmrun_cmd, shell=True) 
    
  2. Cambio vmrun_cmd en otra parte de su código

  3. Conseguir este error algo dentro de vmware-cmd.bat

cosas para probar:

  • Abra un símbolo del pitón, ejecute el siguiente comando:

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

Si funciona, a continuación, citando problemas están fuera de la cuestión. Si no, has aislado el problema.

+0

En orden: 1: Me mantuve explícitamente lejos de establecer shell = True, para que no es así? 2: vmrun_cmd es una constante global utilizada exactamente de la misma manera cada vez. 3: No. El ejecutable no se ha invocado cuando se produce el error, es el comienzo de la cadena que especifica su ruta. –

+0

@Rob Carr: edité mi respuesta, por favor intente con el código anterior – nosklo

1

Creo que list2cmdline(), que está haciendo el procesamiento de su lista args, divide cualquier cadena arg en el espacio en blanco a menos que la cadena contenga comillas dobles. Así que esperaría

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

para ser lo que quieras.

También es probable que desee rodear los otros argumentos (como target_vm) entre comillas dobles en el supuesto de que, también, cada uno representa un arg distinto para presentar a la línea de comandos. Algo así como

r'"%s"' % target_vm 

(por ejemplo) debería ser adecuado.

Ver the list2cmdline documentation

D'A

+0

Bueno, target_vm es un argumento, en lugar de una constante, entonces, ¿cuál es el mejor método para hacer doble cotización en esa situación? –

+0

Probablemente lo formule como r '"% s"'% target_vm – darch

+0

Hombre, eso es difícil de leer en el comentario. Moviéndolo a la respuesta. – darch

-2

sugerencia Posiblemente estúpida, pero tal vez intente lo siguiente, para eliminar subproceso + espacios de la ecuación:

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] 

También podría ser vale la pena probar.

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

En Python en MS Windows, el subp La clase rocess.Popen usa la API CreateProcess para iniciar el proceso. CreateProcess toma una cadena en lugar de algo así como una matriz de argumentos. Python usa subprocess.list2cmdline para convertir la lista de argumentos en una cadena para CreateProcess.

Si yo fuera usted, vería lo que devuelve subprocess.list2cmdline (args) (donde args es el primer argumento de Popen). Sería interesante ver si está poniendo citas alrededor del primer argumento.

Por supuesto, esta explicación podría no aplicarse en un entorno Cygwin.

Habiendo dicho todo esto, no tengo MS Windows.

-1

Esto es lo que no me gusta espacios

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

que tienes en el nombre del comando en sí - que es desconcertante su concha. Por lo tanto, el "'c: \ Program' no se reconoce como un comando interno o externo, programa operable o archivo por lotes."

Opción 1: coloque su archivo .BAT en otro lugar. De hecho, ponga todo su VMWare en otro lugar. Aquí está la regla: No utilice el directorio "Archivos de programa" para nada. Simplemente está mal.

Opción 2 - citar el valor vmrun_cmd

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

Si tiene espacios en la ruta, la manera más fácil que he encontrado para conseguir que interpretan correctamente es esto.

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

No sé exactamente por qué se necesitan comillas dobles dobles, pero eso es lo que funciona.

0

Un problema es que si el comando está rodeado de comillas y no tiene espacios, también podría confundir el shell.

Así que hago esto:

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

cmd = fmt % raw_cmd 
0

Eso era un problema bastante difícil para los últimos tres .... nada nuestro trabajo hasta ahora declarado lo hizo, ni el uso de r "" o Popen con una lista y por lo en. Lo que funcionó al final fue una combinación de cadena de formato y r "". Así que mi solución es la siguiente:

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

donde ambas variables pathToExe y pathToVideoFileOrDir tienen espacios en blanco en su camino. El uso de \ "dentro de la cadena formateada no funcionó y produjo el mismo error que la primera ruta no detectada más correctamente.

Cuestiones relacionadas