2012-02-17 10 views
5

Sto scrivendo un wrapper per automatizzare alcuni comandi della shell ADB di Android tramite Python (2.7.2). Poiché, in alcuni casi, ho bisogno di eseguire il comando in modo asincrono, sto usando il metodo subprocess. Open per emettere comandi di shell.subprocess.Popen e shlex.split formattazione in windows e linux

ho incontrato un problema con la formattazione del parametro [command, args] del metodo Popen, dove ci richiedono di comando/args spaccatura è diverso tra Windows e 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 

Ho provato con shlex .split(), con e senza il flag posix:

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

Entrambi i casi restituiscono lo stesso split.

Esiste un metodo in subprocess o shlex che gestisce i formati specifici del sistema operativo correttamente?

Questa è la mia soluzione attuale:

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() 

non credo shlex.split() sta facendo nulla qui, e cmd.split() ottiene risultati identici.

+0

Hai fatto un errore di battitura nella domanda. shlex vs shelx. – jgritty

+0

@jgritty grazie. Corretto. –

+1

perché usi 'shell = True'? – jfs

risposta

5

Essi sembrano funzionare in modo identico quando spengo shell=True

Come per la documentazione:

In Unix, con Shell = True: Se args è una stringa , specifica la stringa di comando da eseguire attraverso la shell. Ciò significa che la stringa deve essere formattata esattamente come sarebbe quando viene digitata al prompt della shell . Ciò include, ad esempio, la citazione o il backslash di nomi file di escape con spazi al loro interno. Se args è una sequenza, il primo elemento di specifica la stringa di comando e tutti gli articoli aggiuntivi saranno trattati come argomenti aggiuntivi alla shell stessa . Vale a dire , Popen fa l'equivalente di:

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

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

+1

La shell che accetta gli argomenti, piuttosto che il comando da essa eseguito, spiega il problema (e la soluzione) perfettamente. Con 'shell = False'' args = cmd.split() 'e' subprocess.Popen (args, shell = False) 'si comportano in modo identico sia su linux che su windows. –

4

L'argomento shell=True indica che la riga di comando deve essere valutata dalla shell, che su Windows sarà Cmd.exe; su Linux, probabilmente sarà /bin/bash, ma potrebbe anche essere un'altra shell correlata (zsh, tcsh, ecc.). La differenza di comportamento è probabilmente causata dalle shell che interpretano i comandi in modo diverso.

Consiglio vivamente non utilizzando shell=True se è possibile evitarlo. Solo qualcosa di simile:

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