【问题标题】:subprocess.Popen and shlex.split formatting in windows and linuxWindows 和 linux 中的 subprocess.Popen 和 shlex.split 格式
【发布时间】:2012-02-17 02:30:51
【问题描述】:

我正在编写一个包装器来通过 Python (2.7.2) 自动执行一些 android ADB shell 命令。 由于在某些情况下,我需要异步运行命令,因此我使用 subprocess.Popen 方法来发出 shell 命令。

我遇到了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() 取得了相同的结果。

【问题讨论】:

  • 您在问题中打错了字。 shlex 与 shelx。
  • @J.F.Sebastian 之前版本的(完整)代码实际上没有它就失败了。我现在改了shell=False。谢谢你的评论。
  • 不相关:s.communicate() 是一个阻塞调用,它等待进程终止(它不是异步的),因此您可以使用output = subprocess.check_output(args, stderr=STDOUT) 而不是output = o.read()
  • @J.F.Sebastian 我知道。这里的示例命令不是连续的,并且在进程终止之前有 s.communicate 阻塞是有意义的。异步情况将捕获geteventlogcat 的输出,直到从PC 客户端发出终止命令。 (严格来说,你不需要为 logcat 执行此操作,因为您可以读取日志文件,但您为 getevent 执行此操作。)
  • s.split()shlex.split(s) 不相同!例如,尝试在 Python 控制台中比较以下内容:shlex.split('echo "foo bar is fun $(ls /tmp)"', posix=False)'echo "foo bar is fun $(ls /tmp)"'.split()。经典的 str.split() 方法在逻辑上拆分字符串,但 shlex.split(str) 模块智能拆分字符串 - 正如 Shell 所理解的那样。

标签: python subprocess shlex


【解决方案1】:

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

根据文档:

在 Unix 上,shell=True:如果 args 是一个字符串,它指定 要通过 shell 执行的命令字符串。这意味着 字符串的格式必须与在 外壳提示符。这包括,例如,引用或反斜杠 转义带有空格的文件名。如果 args 是一个序列,则 第一项指定命令字符串,任何其他项将 被视为 shell 本身的附加参数。那就是 比如说,Popen 相当于:

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

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

【讨论】:

  • 接受参数的shell,而不是它执行的命令,完美地解释了问题(和解决方案)。使用 shell=False args = cmd.split()subprocess.Popen(args, shell=False) 在 linux 和 windows 上的行为相同。
【解决方案2】:

shell=True 参数告诉它让您的 shell 评估命令行,在 Windows 上将为 Cmd.exe;在 Linux 上,它可能是 /bin/bash,但也可能是其他一些相关的 shell(zsh、tcsh 等)。行为上的差异可能是由于 shell 对命令的解释不同造成的。

如果可以避免的话,我强烈建议不要使用shell=True。就像这样:

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

【讨论】:

  • 不幸的是,在某些情况下 cmd.split() 会失败,即当参数有空格时,如cmd='/usr/bin/ls "/home/user/my directory"' 会因 cmd.split() 而失败。在这种情况下,cmd = shlex.split(cmd, posix=True) 会更好。但是当标准输出被捕获时 shlex.split() 将失败,因此没有全能解决方案恕我直言。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-18
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多