子进程模块无法运行命令

时间:2011-10-25 10:57:57

标签: python python-3.x subprocess

我正在尝试在一组文件上执行Google的cpplint.py,并将结果收集到一个日志文件中。但是,我还没有成功击败子进程模块。我目前的代码在这里:

import os, subprocess

rootdir = "C:/users/me/Documents/dev/"
srcdir = "project/src/"

with open(rootdir+srcdir+"log.txt", mode='w', encoding='utf-8') as logfile:
    for subdir, dirs, files in os.walk(rootdir+srcdir):
        for file in files:
            if file.endswith(".h") or file.endswith(".cpp"):
                filewithpath=os.path.join(subdir, file)
                cmd=['c:/Python27/python.exe','C:/users/me/Documents/dev/cpplint.py','--filter=-whitespace,-legal,-build/include,-build/header_guard/', filewithpath]               
                output = subprocess.check_output(cmd)
                logfile.write(output.decode('ascii'))

尝试运行上面的代码会引发错误:

  File "C:\Python32\lib\site.py", line 159
    file=sys.stderr)
        ^ SyntaxError: invalid syntax Traceback (most recent call last):   File "C:\Users\me\Documents\dev\project\src\verifier.py", line 19, in <module>
    output = subprocess.check_output(cmd)   File "C:\Python32\lib\subprocess.py", line 511, in check_output
    raise CalledProcessError(retcode, cmd, output=output) subprocess.CalledProcessError: Command '['c:/Python27/python.exe', 'C:/users/me/Documents/dev/cpplint.py', '--filter=-whitespace,-legal,-build/include,-build/header_guard/', 'C:/users/me/Documents/dev/project/src/aboutdialog.cpp']' returned non-zero exit status 1

如果我用简单的东西代替cmd:

cmd=['C:/WinAVR-20100110/bin/avr-gcc.exe','--version']

然后脚本按预期工作。

我还尝试使用单个命令字符串而不是字符串列表作为cmd,但结果是相同的。 在调试代码时,我从调试器复制了list-of-strings-turned-into-the-command-line-command并在Windows命令行中运行它,命令按预期运行。

运行我的脚本的Python解释器是Python 3.2。 任何提示都非常感谢。

3 个答案:

答案 0 :(得分:11)

看起来cpplint.py只是退出非零返回代码 - 例如,如果它在正在检查的源文件中发现错误或“lint”,它可能会这样做。

请参阅subprocess.check_output的文档。请注意,如果执行的命令返回非零退出代码,则会引发subprocess.CalledProcessError

你可以通过观察CalledProcessError来解决这个问题,例如

try:
    output = subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
    # ack!  cpplint.py failed... report an error to the user?

修改

SyntaxError似乎是关键所在,可能是由C:\Python32\lib在你的PYTHONPATH中引起的(显式,或者,如果它是你当前的工作目录,可能会发生这种情况)。

Python解释器(大约1.5.2-ish)在启动时会自动运行import site。因此,在这种情况下,您的脚本将执行:

c:/Python27/python.exe C:/users/me/Documents/dev/cpplint.py ...

然后 Python 2.7 解释器将首先找到C:\Python32\lib\site.py,并尝试加载它,而不是C:\Python27\lib\site.py处的那个(大概)。问题是Python 3的site.py包含与Python 2不兼容的语法,因此subprocess.check_output启动的进程在它甚至有机会运行cpplint之前就会失败并出现一个SyntaxError,这会传播CalledProcessError

解决方案?确保Python2获得了真正的Python2“PYTHONPATH”,同样适用于Python3!换句话说,运行Python2解释器时,请确保C:\Python32\lib不在PYTHONPATH搜索路径中。

在您的情况下执行此操作的一种方法是在启动流程时设置显式环境,例如:

python2_env = {"PYTHONPATH": "path/to/python2/stuff:..."}
output = subprocess.check_output(cmd, env=python2_env)

答案 1 :(得分:1)

我会要求你先运行

pipe = subprocess.Popen([cmd, options],stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = pipe.communicate()

您将了解其背后的错误究竟是什么,因为仅当退出代码为非零时才会引发CalledProcessError。

答案 2 :(得分:1)

我通过使用以下内容替换def main()来实现它(我编辑错误函数以获得正确的csv文件):

errorlog = sys.stderr
sys.stderr = open("errorlog.csv","w")
sys.stderr.write("File;Line;Message;Category;Confidence\n")
for filename in filenames:
  ProcessFile(filename, _cpplint_state.verbose_level)
_cpplint_state.PrintErrorCounts()
sys.exit(_cpplint_state.error_count > 0)
sys.stdout = errorlog
sys.stderr.close()