麻烦从python中调用bash

时间:2012-03-21 21:17:01

标签: android python bash shell

我正在尝试使用python来帮助围绕Android构建系统中的增量构建功能进行一些自动化。通常,从给定目录,我将执行以下命令来构建该目录和子目录中的任何内容:

mm -j8

这类似于“make”命令,只是它是增量构建,并被定义为名为envsetup.sh的bash文件中的函数。什么是不重要的,只要知道它是在文件系统中某处的bash脚本中定义的函数。要执行此操作,我也可以这样做:

bash -c ". /path/to/envsetup.sh; mm -j8"

这种调用它的方法在从python调用函数时很重要。我已经按照解决方案here展示了如何从python中调用bash脚本中的函数。我在一个简单的脚本中使用了这个方法,理论上,它应该只是吐出STDOUT和STDERR来执行命令:

import subprocess

command = ['bash', '-c', '. /path/to/envsetup.sh; mm -j8']
(stdout, stderr) = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()

print 'stdout: ' + stdout
print 'stderr: ' + stderr

然而,对Popen的调用永远不会返回。我做错了什么才能让bash正确执行命令,但Python在执行命令时会挂起?

1 个答案:

答案 0 :(得分:3)

TL; DR:

您的问题是使用shell=True。将其设置为shell=False,它就会起作用。

设置此选项后,python将只运行command数组的第一个元素,即bash作为shell脚本。所以目前,python正在启动它自己的shell,以便运行你的命令(bash)。它将运行没有参数的bash,然后bash将等待输入,阻止你的python脚本。

shell=True设置适用于将shell脚本作为单个字符串传递的用例。当您明确指定shell及其参数作为要调用的进程时,如上所述,您应该设置shell=False

>>> import subprocess
>>> subprocess.Popen(['bash', 'whatever'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()

以下是运行上述内容时进程树的样子:

  \_ python
      \_ /bin/sh -c bash whatever
          \_ bash

whatever实际上已传入,但它是sh的参数,而不是内部bash的参数,因此正在运行的命令实际上是['/bin/sh', '-c', 'bash', 'whatever'] ,这与['/bin/sh', '-c', 'bash whatever']

完全不同