将所有stdout存储到文件,同时仍然在屏幕上显示它

时间:2014-03-26 22:14:11

标签: python stdout

python外,所有语言似乎都有问题/答案(至少我还没找到)

从这个问题Redirect stdout to a file in 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-如何在屏幕上显示存储的输出

4 个答案:

答案 0 :(得分: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'

答案 1 :(得分:2)

因此,您可以使用自定义重定向类来模拟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()

这将允许您拦截打印语句并使用它们执行您喜欢的操作。您甚至可以在消息中添加自定义标记,以指定它们应该转到哪些输出设备。但是,正如我在上面的评论中所说,logging可能是更好的选择。

答案 2 :(得分:1)

要在标准输出上输出上一次,只需将sys.stdout分配给标准输出文件流。

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')

答案 3 :(得分:1)

这会产生预期的结果。

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'

标准输出

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