【问题标题】:Store all stdout to file while still displaying it on screen将所有标准输出存储到文件中,同时仍将其显示在屏幕上
【发布时间】:2014-03-26 22:14:11
【问题描述】:

除了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- 我怎样才能让存储的输出显示在屏幕上?

【问题讨论】:

标签: python stdout


【解决方案1】:

包装很性感

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'

【讨论】:

    【解决方案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()
    

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

    【讨论】:

      【解决方案3】:

      为了在标准输出上输出最后一次,只需将 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')
      

      【讨论】:

        【解决方案4】:

        这会产生预期的结果。

        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
        

        【讨论】:

          猜你喜欢
          • 2013-10-16
          • 1970-01-01
          • 2021-04-28
          • 1970-01-01
          • 2011-11-08
          • 2018-01-09
          • 2011-10-12
          • 2012-09-09
          相关资源
          最近更新 更多