Windows和Linux中subprocess.Popen与shlex.split的格式化

7 投票
2 回答
30129 浏览
提问于 2025-04-17 13:09

我正在写一个工具,用Python(2.7.2)来自动化一些安卓的ADB命令。因为有时候我需要异步运行这些命令,所以我使用了subprocess模块中的Popen方法来执行命令。

我遇到了一个问题,就是在使用Popen方法时,[command, args]这个参数的格式在Windows和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

我尝试过使用shlex的split()方法,试过带和不带posix标志的情况:

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

这两种情况返回的分割结果是一样的。

有没有什么方法可以在subprocessshlex中正确处理不同操作系统的格式呢?

这是我现在的解决方案:

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

我觉得shlex.split()在这里没有起到作用,而cmd.split()的结果是一样的。

2 个回答

5

shell=True这个参数的意思是让你的命令行通过你的命令行解释器来执行。在Windows上,这个解释器是Cmd.exe;而在Linux上,通常是/bin/bash,但也可能是其他相关的解释器,比如zsh、tcsh等等。不同的解释器可能会以不同的方式来理解和执行命令,这就是为什么会有不同的表现。

如果可以的话,我强烈建议你不要使用shell=True。你可以用类似下面的方式来做:

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

当我关闭 shell=True 时,它们似乎功能完全相同。

根据文档的说明:

在Unix系统中,如果使用 shell=True:如果 args 是一个字符串,那它就是要通过命令行执行的命令字符串。这意味着这个字符串必须和你在命令行提示符下输入时完全一样。这包括,比如说,文件名中有空格的情况,你需要用引号或者反斜杠来转义。如果 args 是一个序列(比如列表),那么第一个项目就是命令字符串,后面的项目会被当作额外的参数传给命令行本身。换句话说,Popen 做的事情相当于:

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

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

撰写回答