我正在为不同语言的源代码进行静态分析。由于任何东西必须是开源的并且可以从命令行调用,我现在已经为每种语言下载了一个工具。所以我决定编写一个python脚本,列出项目文件夹中的所有源文件并调用相应的工具。
因此我的部分代码如下所示:
import os
import sys
import subprocess
from subprocess import call
from pylint.lint import Run as pylint
class Analyser:
def __init__(self, source=os.getcwd(), logfilename=None):
# doing initialization stuff
self.logfilename = logfilename or 'CodeAnalysisReport.log'
self.listFiles()
self.analyseFiles()
def listFiles(self):
# lists all source files in the specified directory
def analyseFiles(self):
self.analysePythons()
self.analyseCpps()
self.analyseJss()
self.analyseJavas()
self.analyseCs()
if __name__ == '__main__':
Analyser()
让我们来看看C ++文件部分(我使用Cppcheck来分析它们):
def analyseCpps(self):
for sourcefile in self.files['.cc'] + self.files['.cpp']:
print '\n'*2, '*'*70, '\n', sourcefile
call(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile])
其中一个文件(它只是一个随机下载的文件)的控制台输出是:
**********************************************************************
C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc
Checking C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc...
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:18]: (style) The scope of the variable 'oldi' can be reduced.
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:43]: (style) The scope of the variable 'lastbit' can be reduced.
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:44]: (style) The scope of the variable 'two_to_power_i' can be reduced.
(information) Cppcheck cannot find all the include files (use --check-config for details)
第1行和第2行来自我的脚本,第3行到第7行来自Cppcheck。
这就是我想要保存到我的日志文件中的所有其他文件。一切都在一个文件中。
当然我搜索了SO并找到了一些方法。但没有一个完全奏效。
首先尝试:
将sys.stdout = open(self.logfilename, 'w')
添加到我的构造函数中。这使得上面显示的输出的第1行和第2行被写入我的日志文件。其余的仍然显示在控制台上。
第二次尝试:
另外,在analyseCpps
我使用:
call(['C:\CodeAnalysis\cppcheck\cppcheck', '--enable=all', sourcefile], stdout=sys.stdout)
这使我的日志文件为:
Checking C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc...
**********************************************************************
C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc
,控制台输出为:
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:18]: (style) The scope of the variable 'oldi' can be reduced.
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:43]: (style) The scope of the variable 'lastbit' can be reduced.
[C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc:44]: (style) The scope of the variable 'two_to_power_i' can be reduced.
不是我想要的。
第三次尝试:
将Popen
与pipe
一起使用。 sys.stdout
恢复默认。
正如初步工作analyseCpps
现在是:
for sourcefile in self.files['.cc'] + self.files['.cpp']:
print '\n'*2, '*'*70, '\n', sourcefile
p = subprocess.Popen(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile], stdout=subprocess.PIPE)
p.stdout.read()
p.stdout.read()
仅显示我所需输出的最后一行(代码框3中的第7行)
第四次尝试:
使用subprocess.Popen(['C:\CodeAnalysis\cppcheck\cppcheck', '--enable=all', sourcefile], stdout=open(self.logfilename, 'a+'))
只将一行Checking C:\CodeAnalysis\testproject\cpp\BiggestUnInt.cc...
写入我的日志文件,其余行显示在控制台上。
第五次尝试:
而不是subprocess.Popen
我使用os.system
,所以我的调用命令是:
os.system('C:\CodeAnalysis\cppcheck\cppcheck --enable=all %s >> %s' % (sourcefile, self.logfilename))
这导致与第四次尝试相同的日志文件。如果我直接在Windows控制台中键入相同的命令,结果是相同的。所以我猜这不是一个蟒蛇问题,但仍然是:
如果它在控制台上,必须有办法将其放入文件中。 有什么想法吗?
E D I T
愚弄我。我还是个菜鸟,所以我忘记了stderr
。这就是决定性信息的发展方向。
所以现在我有:
def analyseCpps(self):
for sourcefile in self.files['.cc'] + self.files['.cpp']:
p = subprocess.Popen(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile], stderr=subprocess.PIPE)
with open(self.logfilename, 'a+') as logfile:
logfile.write('%s\n%s\n' % ('*'*70, sourcefile))
for line in p.stderr.readlines():
logfile.write('%s\n' % line.strip())
它工作正常。
另一个编辑
根据Didier的回答:在我的构造函数中使用sys.stdout = open(self.logfilename, 'w', 0)
:
def analyseCpps(self):
for sourcefile in self.files['.cc'] + self.files['.cpp']:
print '\n'*2, '*'*70, '\n', sourcefile
p = subprocess.Popen(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile], stdout=sys.stdout, stderr=sys.stdout)
答案 0 :(得分:2)
有几个问题:
这样的事情:
import sys, subprocess
# Note the 0 here (unbuffered file)
sys.stdout = open("mylog","w",0)
print "Hello"
print "-----"
subprocess.call(["./prog"],stdout=sys.stdout, stderr=sys.stdout)
print "-----"
subprocess.call(["./prog"],stdout=sys.stdout, stderr=sys.stdout)
print "-----"
print "End"
答案 1 :(得分:1)
您还需要重定向stderr,您可以使用STDOUT
或将文件对象传递给stderr =:
from subprocess import check_call,STDOUT
with open("log.txt","w") as f:
for sourcefile in self.files['.cc'] + self.files['.cpp']:
check_call(['C:\\CodeAnalysis\\cppcheck\\cppcheck', '--enable=all', sourcefile],
stdout=f, stderr=STDOUT)
答案 2 :(得分:1)
尝试将-e for error
-X for debug
-q for only error
和stdout
重定向到日志文件:
stderr
在此示例中,文件名是硬编码的,但您应该可以轻松更改(到import subprocess
def analyseCpps(self):
with open("logfile.txt", "w") as logfile:
for sourcefile in self.files['.cc'] + self.files['.cpp']:
print '\n'*2, '*'*70, '\n', sourcefile
call(['C:\\CodeAnalysis\\cppcheck\\cppcheck',
'--enable=all', sourcefile], stdout=logfile,
stderr=subprocess.STDOUT)
或类似)。