2012-02-17 14 views
5

Piszę wrapper, aby zautomatyzować niektóre polecenia powłoki ADB systemu Android za pośrednictwem Pythona (2.7.2). Ponieważ w niektórych przypadkach muszę uruchomić polecenie asynchronicznie, używam metody subprocess .Popen do wydawania poleceń powłoki.formatowanie podprocesu.Plex i shlex.split w systemie Windows i Linux

mam napotkasz problem z formatowaniem parametru metody Popen, gdzie nie wymaga dowodzenia/ARG rozłamu [command, args] różni się między Windows i 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 

Próbowałem, używając shlex .split(), z zewnątrz i z flagą posix:

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

Oba przypadki zwracają ten sam podział.

Czy istnieje metoda w subprocess lub shlex, która obsługuje formaty specyficzne dla systemu operacyjnego poprawnie?

To jest mój obecny rozwiązanie:

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

Nie sądzę shlex.split() robi nic tutaj i cmd.split() osiąga identyczne wyniki.

+0

Wprowadziłeś literówkę w pytaniu. shlex vs shelx. – jgritty

+0

@jgritty dzięki. Poprawione. –

+1

dlaczego używasz 'shell = True'? – jfs

Odpowiedz

5

Wydają się działać identycznie kiedy wyłączyć shell=True

Zgodnie docs:

Na Unix, z powłoką = True: Jeżeli args jest ciągiem , określa ciąg poleceń, który ma być wykonywany przez powłokę. Oznacza to, że ciąg znaków musi być sformatowany dokładnie tak, jak byłby po wpisaniu w wierszu poleceń powłoki . Obejmuje to na przykład cytowanie lub ukośnik odwrotny wymazanie nazw plików ze spacjami. Jeśli argumentem jest sekwencja, pierwszy element określa ciąg poleceń, a wszelkie dodatkowe elementy będą traktowane jako dodatkowe argumenty dla samej powłoki. To powiedzieć, Popen robi równowartość:

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

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

+1

Powłoka pobierająca argumenty, a nie polecenie wykonane przez nią, wyjaśnia problem (i rozwiązanie) idealnie. Przy 'shell = False'' args = cmd.split() 'i' subprocess.Popen (args, shell = False) 'zachowują się identycznie zarówno w systemie Linux, jak i Windows. –

4

Argument informuje, że linia poleceń powinna być oceniona przez powłokę, która w systemie Windows będzie miała postać Cmd.exe; w Linuksie prawdopodobnie będzie to /bin/bash, ale może być też inną powiązaną powłoką (zsh, tcsh, itp.). Różnica w zachowaniu jest prawdopodobnie spowodowana przez powłoki interpretujące polecenia w inny sposób.

Zdecydowanie polecam nie przy użyciu shell=True, jeśli możesz tego uniknąć. Właśnie coś takiego:

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