python脚本使用子流程,将所有输出重定向到文件
我正在为不同语言的源代码的静态分析写一些东西。由于任何东西都必须是开源的,并且可以从命令行调用,我现在下载了每种语言一个工具。因此,我决定编写一个python脚本,列出项目文件夹中的所有源文件,并调用相应的工具 我的部分代码如下所示:python脚本使用子流程,将所有输出重定向到文件,python,file-io,console,subprocess,cppcheck,Python,File Io,Console,Subprocess,Cppcheck,我正在为不同语言的源代码的静态分析写一些东西。由于任何东西都必须是开源的,并且可以从命令行调用,我现在下载了每种语言一个工具。因此,我决定编写一个python脚本,列出项目文件夹中的所有源文件,并调用相应的工具 我的部分代码如下所示: import os import sys import subprocess from subprocess import call from pylint.lint import Run as pylint class Analyser: def
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()
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"
让我们看看C++文件部分(我使用CPPCHECK来分析这些):
其中一个文件(只是随机下载的文件)的控制台输出为: 第1行和第2行来自我的脚本,第3行到第7行来自Cppcheck 这就是我想保存到日志文件中的内容,对于所有其他文件也是如此。所有内容都在一个文件中 当然,我已经找到了一些方法。但没有一个能完全发挥作用 第一次尝试: 将sys.stdout=open(self.logfilename,'w')添加到我的构造函数中。这使得上面显示的输出的第1行和第2行被写入我的日志文件。其余部分仍显示在控制台上 第二次尝试: 此外,在分析PPS
中,我使用:
调用(['C:\codesanalysis\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
与管道一起使用
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:\code分析\cppcheck\cppcheck','--enable=all',sourcefile],stdout=open(self.logfilename,'a+'))
只需将一行检查C:\code分析\testproject\cpp\BiggestUnInt.cc…
写入我的日志文件,其余部分显示在控制台上
第五次尝试:
我使用的不是subprocess.Popen
,而是os.system
,因此我的调用命令是:
os.system('C:\CodeAnalysis\cppcheck\cppcheck--enable=all%s>>%s'(sourcefile,self.logfilename))
这将产生与第四次尝试相同的日志文件。如果我直接在windows控制台中键入相同的命令,结果是相同的。因此,我想这并不完全是python的问题,但仍然:
如果它在控制台上,必须有办法将其放入文件。有什么想法吗
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())
它工作得很好
另一次编辑 根据迪迪埃的回答: 在我的构造函数中使用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)
您也需要重定向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)
尝试将
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)
在本例中,文件名是硬编码的,但您应该能够轻松地更改(更改为
self.logfilename
或类似文件名)。有几个问题:
- 您应该重定向stdout和stderr
- 如果要混合普通打印和已启动命令的输出,应使用无缓冲文件
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()
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"
嗯,我刚刚意识到,这些消息会被发送到stderr,我正要自己键入一个答案:-)。所以你是对的。我将编辑答案中的工作代码。感谢您的快速评论和回答,您一切正常。相关:无关:不要对p.stderr.readlines()中的行使用
,只对p.stderr中的行使用:
。此外,您还可以编写shutil.copyfileobj(p.stderr,logfile)
。此外,还可以使用stderr=subprocess.STDOUT
。此外,您还可以--在本例中删除stdout
,stderr
参数--它们是自动处理的。这实际上很酷。我将重新更改我的实现。@seesharp:手动重定向每个子进程调用的输出似乎很脆弱,如果某些代码直接写入stdout(os.write(1,b“不会捕获我”)
),则会失败。更好的替代方法是重定向运行Python脚本的代码中的输出:Python your_script.py&>log
(bash)或使用os.dup2()
重定向(也适用于Windows)。请参阅我对您的问题的评论中的链接。我使用的是Python 2.7(没有提到,真不好意思),因此没有contextlib.redirect\u stdout()
。此外,我决定不将每个输出重定向到一个文件。由于整个脚本需要相当长的时间来运行,我使用print语句来显示进度,并且子流程的输出直接指向我的日志文件。到目前为止,它是有效的,所以我将保持这种方式,但我会记住你的答案,为未来。