我正在尝试使用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在执行命令时会挂起?
答案 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']