2012-02-17 15 views
5

Estoy escribiendo un contenedor para automatizar algunos comandos de shell Android ADB a través de Python (2.7.2). Dado que, en algunos casos, necesito ejecutar el comando de forma asincrónica, estoy usando el método subprocess .Popen para emitir comandos de shell.subprocess.Popen y shlex.split formato en windows y linux

se han topado con un problema con el formato del parámetro [command, args] del método Popen, donde no requieren comando/args división es diferente entre Windows y Linux:

# sample command with parameters 
cmd = 'adb -s <serialnumber> shell ls /system' 

# Windows: 
s = subprocess.Popen(cmd.split(), shell=False) # command is split into args by spaces 

# Linux: 
s = subprocess.Popen([cmd], shell=False) # command is a list of length 1 containing whole command as single string 

He intentado usar shlex .split(), con y sin la marca posix:

# Windows 
posix = False 
print shlex.split(cmd, posix = posix), posix 
# Linux 
posix = True 
print shlex.split(cmd, posix = posix), posix 

Ambos casos devuelven la misma división.

¿Hay un método en el subprocess o shlex que maneja los formatos específicos de OS correctamente?

Esta es mi solución actual:

import os 
import tempfile 
import subprocess 
import shlex 

# determine OS type 
posix = False 
if os.name == 'posix': 
    posix = True 

cmd = 'adb -s <serialnumber> shell ls /system' 
if posix: # posix case, single command string including arguments 
    args = [cmd] 
else: # windows case, split arguments by spaces 
    args = shlex.split(cmd) 

# capture output to a temp file 
o = tempfile.TemporaryFile() 
s = subprocess.Popen(args, shell=False, stdout=o, stderr=o) 
s.communicate() 
o.seek(0) 
o.read() 
o.close() 

no creo shlex.split() está haciendo nada aquí, y cmd.split() logra resultados idénticos.

+0

Hizo un error ortográfico en la pregunta. shlex vs shelx. – jgritty

+0

@jgritty gracias. Corregido –

+1

¿por qué usas 'shell = True'? – jfs

Respuesta

5

Ellos parecen funcionar de forma idéntica cuando apago shell=True

De acuerdo con los documentos:

En Unix, con la cáscara = True: Si args es una cadena , especifica la cadena de comando para ejecutar a través del shell. Esto significa que la cadena debe formatearse exactamente como cuando se escribe en el indicador de shell . Esto incluye, por ejemplo, comillas o barras invertidas escapando nombres de archivos con espacios en ellas. Si args es una secuencia, el primer elemento especifica la cadena de comando, y cualquier elemento adicional se tratará como argumentos adicionales para el propio shell . Esto quiere decir , Popen hace el equivalente de:

Popen ([ '/ bin/sh', '-c', args [0], args [1], ...])

http://docs.python.org/library/subprocess.html

+1

El shell que toma los argumentos, en lugar del comando ejecutado por él, explica el problema (y la solución) perfectamente. Con 'shell = False'' args = cmd.split() 'y' subprocess.Popen (args, shell = False) 'se comportan de manera idéntica tanto en Linux como en Windows. –

4

El argumento shell=True indica que la línea de comandos debe ser evaluada por su shell, que en Windows será Cmd.exe; en Linux, probablemente sea /bin/bash, pero también podría ser algún otro shell relacionado (zsh, tcsh, etc.). La diferencia en el comportamiento probablemente se deba a que los proyectiles interpretan los comandos de forma diferente.

Recomiendo encarecidamente no usando shell=True si puede evitarlo. Sólo algo como esto:

cmd = 'adb -s <serialnumber> shell ls /system' 
s = subprocess.Popen(cmd.split()) # shell=False by default 
Cuestiones relacionadas