将所有标准输出存储到文件中,同时仍在屏幕上显示



这里似乎有一个问题/答案除了python(至少我还没有找到它)

从这个问题重定向stdout到一个文件在Python?我了解到,为了将所有输出从屏幕重定向到一个文件,我只需要使用:

import sys
some_list = ['elem1', 'elem2']
for elem in some_list:
    sys.stdout = open(elem + '.log', 'w')
    # Do lots of stuff that print messages.
    print 'lots of stuff for', elem
print 'Code finished'

将所有输出存储到elemx.log文件中:

elem1.log
lots of stuff for elem1
elem2.log
lots of stuff for elem2
Code finished

关于这种方法我有两个问题:

1-我如何使最后一行打印行(即:Code finished) 存储在为最后一个elem创建的文件中?

2-我怎么能有存储的输出显示在屏幕上?

包装纸很性感

import sys
class Logger(file):
    def __init__(self,*a,**kw):
        # copy original stdout to instance
        self.stdout = sys.stdout
        return super(Logger,self).__init__(*a,**kw)
    def write(self,data):
        self.stdout.write(data) # to screen
        return super(Logger,self).write(data) #to file
    def writelines(self,lines):
        for line in lines: self.write(line)
    def close(self):
        # return it back
        sys.stdout = self.stdout

some_list = ['elem1', 'elem2']
for elem in some_list:
    with Logger("/tmp/1/{}.log".format(elem), "w") as sys.stdout:
    # Do lots of stuff that print messages.
        print 'lots of stuff for', elem

print 'Code finished'
结果

$ python2 out.py 
Code finished
$ ls
elem1.log  elem2.log  out.py

酷的副作用:

print 'this on screen'
with Logger("/tmp/1/main.log", "w") as sys.stdout:
     print 'this on screen an in main.log'
     with Logger("/tmp/1/sub.log", "w") as sys.stdout:
          print 'this on screen, in man.log and in sub.log'
print 'only on screen again'

因此,您可以使用自定义重定向类来模拟unix tee功能:

import sys
import os
class OutputRedirect(object):
    def __init__(self):
        self.output_devices = []
    def add_device(self,name):
        self.output_devices.append(open(name,"w+"))
    def remove_device(self,name):
        idx = [f.name for f in self.output_devices].index(name)
        self.output_devices.pop(idx)
    def write(self,msg):
        for device in self.output_devices:
            device.write(msg)
    def __del__(self):
        for device in self.output_devices:
            device.close()

def main():
    outputs = OutputRedirect()
    outputs.add_device("test.txt")
    outputs.add_device("/dev/stdout")
    sys.stdout = outputs
    print "this is a test"
    print "this is another test"
    outputs.remove_device("test.txt")
    print "this is not written to file"
if __name__ == "__main__":
    main()

这将允许您拦截print语句并对它们执行您喜欢的操作。您甚至可以向消息添加自定义标记,以指定它们应该发送到哪个输出设备。然而,正如我在上面的评论中所说,logging可能是一个更好的选择。

对于最后一次在标准输出上输出,只需赋值sys。标准输出到标准输出文件流。

import sys
some_list = ['elem1', 'elem2']
for elem in some_list:
    sys.stdout = open(elem + '.log', 'w')
    # Do lots of stuff that print messages.
    print 'lots of stuff for', elem
sys.stdout = open("/dev/stdout", "w")
print 'Code finished'

对于第二个问题,我认为除了将这些行打印两次之外,没有其他解决方案了,一次在标准输出中,另一次在文件中。

import sys
some_list = ['elem1', 'elem2']
for elem in some_list:
    f = open(elem + '.log', 'w')
    # Do lots of stuff that print messages.
    print 'lots of stuff for '+ elem
    f.write( 'lots of stuff for '+ elem)

print 'Code finished'
f.write( 'Code finished')

这会产生期望的结果。

import sys
some_list = ['elem1', 'elem2']
for elem in some_list:
    with open(elem + '.log', 'w') as f:
        # Do lots of stuff that print messages.
        f.write('lots of stuff for ' + elem)
        print 'lots of stuff for', elem
print 'Code finished'

stdout

lots of stuff for elem1
lots of stuff for elem2
Code finished

elem1.log

lots of stuff for elem1

elem2.log

lots of stuff for elem2

最新更新