2012-02-17 30 views
5

Tôi đang viết một trình bao bọc để tự động hóa một số lệnh shell ADB android thông qua Python (2.7.2). Vì, trong một số trường hợp, tôi cần chạy lệnh không đồng bộ, tôi đang sử dụng phương thức subprocess .Popen để đưa ra các lệnh shell.subprocess.Popen và định dạng shlex.split trong cửa sổ và linux

Tôi đã chạy vào một vấn đề với các định dạng của [command, args] tham số của phương pháp Popen, nơi có yêu cầu lệnh/args chia là khác nhau giữa Windows và 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 

Tôi đã cố gắng sử dụng shlex .split(), có và bằng cờ posix:

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

Cả hai trường hợp đều trả lại cùng một phần.

Có một phương pháp trong subprocess hoặc shlex để xử lý các định dạng hệ điều hành cụ thể đúng?

Đây là giải pháp hiện tại của tôi:

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

Tôi không nghĩ shlex.split() đang làm bất cứ điều gì ở đây, và cmd.split() đạt được kết quả giống hệt nhau.

+0

Bạn đã đánh máy trong câu hỏi. shlex vs shelx. – jgritty

+0

@jgritty cảm ơn. Đã sửa. –

+1

tại sao bạn sử dụng 'shell = True'? – jfs

Trả lời

5

Họ dường như hoạt động hệt khi tôi tắt shell=True

Theo các tài liệu:

Trên Unix, với vỏ = True: Nếu args là một chuỗi , nó chỉ định chuỗi lệnh để thực thi thông qua trình bao. Điều này có nghĩa là chuỗi phải được định dạng chính xác như khi được nhập vào dấu nhắc trình bao gồm . Điều này bao gồm, ví dụ: trích dẫn hoặc gạch chéo ngược tên tệp thoát với không gian trong đó. Nếu arg là một chuỗi, thì mục đầu tiên chỉ định chuỗi lệnh và mọi mục bổ sung sẽ được coi là đối số bổ sung cho chính trình bao. Đó là để nói, Popen không tương đương với:

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

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

+1

Shell lấy đối số, chứ không phải lệnh được thực hiện bởi nó, giải thích vấn đề (và giải pháp) một cách hoàn hảo. Với 'shell = False'' args = cmd.split() 'và' subprocess.Popen (args, shell = False) 'hoạt động giống nhau trên cả linux và windows. –

4

Đối số shell=True yêu cầu nó có dòng lệnh được hệ vỏ của bạn đánh giá, mà trên Windows sẽ là Cmd.exe; trên Linux, nó có thể là /bin/bash, nhưng cũng có thể là một số shell liên quan khác (zsh, tcsh, v.v.). Sự khác biệt về hành vi có thể là do các shell giải thích các lệnh khác nhau.

Tôi đặc biệt khuyên bạn nên không sử dụng shell=True nếu bạn có thể tránh. Chỉ cần một cái gì đó như thế này:

cmd = 'adb -s <serialnumber> shell ls /system' 
s = subprocess.Popen(cmd.split()) # shell=False by default 
Các vấn đề liên quan