如何使用脚本将stdout重定向到文件和控制台?

时间:2013-02-16 03:57:55

标签: python-2.7

我想运行一个python脚本并捕获文本文件的输出,并希望在控制台上显示。

我想将它指定为python脚本本身的属性。不要每次都在命令提示符上使用命令echo "hello world" | tee test.txt

在脚本中我试过:

sys.stdout = open('log.txt','w')

但这并没有在屏幕上显示stdout输出。

我听说过记录模块但我无法使用该模块来完成这项工作。

13 个答案:

答案 0 :(得分:97)

执行python文件时可以使用shell重定向:

python foo_bar.py > file

这会将stdout上打印的所有结果从python源写入文件到日志文件。

或者,如果您想要从脚本中进行日志记录:

import sys

class Logger(object):
    def __init__(self):
        self.terminal = sys.stdout
        self.log = open("logfile.log", "a")

    def write(self, message):
        self.terminal.write(message)
        self.log.write(message)  

    def flush(self):
        #this flush method is needed for python 3 compatibility.
        #this handles the flush command by doing nothing.
        #you might want to specify some extra behavior here.
        pass    

sys.stdout = Logger()

现在你可以使用:

print "Hello"

这将为stdout和日志文件

写入“Hello”

答案 1 :(得分:14)

我有办法将输出重定向到控制台以及同时重定向到文本文件:

te = open('log.txt','w')  # File where you need to keep the logs

class Unbuffered:

   def __init__(self, stream):

       self.stream = stream

   def write(self, data):

       self.stream.write(data)
       self.stream.flush()
       te.write(data)    # Write the data of stdout here to a text file as well



sys.stdout=Unbuffered(sys.stdout)

答案 2 :(得分:11)

使用日志记录模块调试并关注您的应用

以下是我如何设法登录文件和控制台/标准输出

import logging
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s',
                    filename='logs_file',
                    filemode='w')
# Until here logs only to file: 'logs_file'

# define a new Handler to log to console as well
console = logging.StreamHandler()
# optional, set the logging level
console.setLevel(logging.INFO)
# set a format which is the same for console use
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
# tell the handler to use this format
console.setFormatter(formatter)
# add the handler to the root logger
logging.getLogger('').addHandler(console)

# Now, we can log to both ti file and console
logging.info('Jackdaws love my big sphinx of quartz.')
logging.info('Hello world')

从源头阅读: https://docs.python.org/2/howto/logging-cookbook.html

答案 3 :(得分:9)

我设计了一个更简单的解决方案。只需定义一个将打印到文件或屏幕或两者都打印的功能。在下面的示例中,我允许用户输入outputfile名称作为参数,但这不是必需的:

OutputFile= args.Output_File
OF = open(OutputFile, 'w')

def printing(text):
    print text
    if args.Output_File:
        OF.write(text + "\n")

在此之后,在文件和/或屏幕上打印一行所需的全部内容是:     印刷(Line_to_be_printed)

答案 4 :(得分:4)

基于Amith Koujalgi's answer,这是一个可用于记录的简单模块 -

transcript.py:

"""
Transcript - direct print output to a file, in addition to terminal.

Usage:
    import transcript
    transcript.start('logfile.log')
    print("inside file")
    transcript.stop()
    print("outside file")
"""

import sys

class Transcript(object):

    def __init__(self, filename):
        self.terminal = sys.stdout
        self.logfile = open(filename, "a")

    def write(self, message):
        self.terminal.write(message)
        self.logfile.write(message)

    def flush(self):
        # this flush method is needed for python 3 compatibility.
        # this handles the flush command by doing nothing.
        # you might want to specify some extra behavior here.
        pass

def start(filename):
    """Start transcript, appending print output to given filename"""
    sys.stdout = Transcript(filename)

def stop():
    """Stop transcript and return print functionality to normal"""
    sys.stdout.logfile.close()
    sys.stdout = sys.stdout.terminal

答案 5 :(得分:2)

from IPython.utils.io import Tee
from contextlib import closing

print('This is not in the output file.')        

with closing(Tee("outputfile.log", "w", channel="stdout")) as outputstream:
    print('This is written to the output file and the console.')
    # raise Exception('The file "outputfile.log" is closed anyway.')
print('This is not written to the output file.')   

# Output on console:
# This is not in the output file.
# This is written to the output file and the console.
# This is not written to the output file.

# Content of file outputfile.txt:
# This is written to the output file and the console.

IPython.utils.io中的Tee课做了你想要的,但缺少在__enter__声明中调用它所需的__exit__with方法。这些是contextlib.closing添加的。

答案 6 :(得分:1)

这种方式在我的情况下非常有效。我只是根据此线程中提供的其他代码添加了一些修改。

import sys, os 

orig_stdout = sys.stdout  # capture original state of stdout

te = open('log.txt','w')  # File where you need to keep the logs

class Unbuffered:
   def __init__(self, stream):
       self.stream = stream

   def write(self, data):
       self.stream.write(data)
       self.stream.flush()
       te.write(data)    # Write the data of stdout here to a text file as well

sys.stdout=Unbuffered(sys.stdout)




#######################################
##  Feel free to use print function  ##
#######################################

print("Here is an Example =)")

#######################################
##  Feel free to use print function  ##
#######################################




# Stop capturing printouts of the application from Windows CMD
sys.stdout = orig_stdout  # put back the original state of stdout
te.flush()  # forces python to write to file
te.close()  # closes the log file

# read all lines at once and capture it to the variable named sys_prints
with open('log.txt', 'r+') as file:
    sys_prints = file.readlines() 

# erase the file contents of log file
open('log.txt', 'w').close()

答案 7 :(得分:0)

要将输出重定向到文件和终端而不修改Python脚本在外部的使用方式,可以使用pty.spawn(itself)

#!/usr/bin/env python
"""Redirect stdout to a file and a terminal inside a script."""
import os
import pty
import sys

def main():
    print('put your code here')

if __name__=="__main__":
    sentinel_option = '--dont-spawn'
    if sentinel_option not in sys.argv:
        # run itself copying output to the log file
        with open('script.log', 'wb') as log_file:
            def read(fd):
                data = os.read(fd, 1024)
                log_file.write(data)
                return data

            argv = [sys.executable] + sys.argv + [sentinel_option]
            rc = pty.spawn(argv, read)
    else:
        sys.argv.remove(sentinel_option)
        rc = main()
    sys.exit(rc)

如果pty模块不可用(在Windows上),那么你可以用teed_call() function替换它,它更便携但是它提供普通管道而不是伪终端 - 它可能会改变行为一些程序。

基于pty.spawnsubprocess.Popen的解决方案优于使用类文件对象替换sys.stdout的优势在于它们可以在文件描述符级别捕获输出,例如,如果脚本启动其他进程,也可以在stdout / stderr上生成输出。请参阅我对相关问题的回答:Redirect stdout to a file in Python?

答案 8 :(得分:0)

这是一个简单的上下文管理器,可打印到控制台并将相同的输出写入文件。还将所有异常写入文件。

import traceback
import sys

# Context manager that copies stdout and any exceptions to a log file
class Tee(object):
    def __init__(self, filename):
        self.file = open(filename, 'w')
        self.stdout = sys.stdout

    def __enter__(self):
        sys.stdout = self

    def __exit__(self, exc_type, exc_value, tb):
        sys.stdout = self.stdout
        if exc_type is not None:
            self.file.write(traceback.format_exc())
        self.file.close()

    def write(self, data):
        self.file.write(data)
        self.stdout.write(data)

    def flush(self):
        self.file.flush()
        self.stdout.flush()

要使用上下文管理器,请执行以下操作:

print("Print")
with Tee('test.txt'):
    print("Print+Write")
    raise Exception("Test")
print("Print")

答案 9 :(得分:0)

我在这里尝试了几种解决方案,但没有找到同时写入文件和控制台的解决方案。这就是我所做的(based on this answer)

class Logger(object):
    def __init__(self):
        self.terminal = sys.stdout

    def write(self, message):
        with open ("logfile.log", "a", encoding = 'utf-8') as self.log:            
            self.log.write(message)
        self.terminal.write(message)

    def flush(self):
        #this flush method is needed for python 3 compatibility.
        #this handles the flush command by doing nothing.
        #you might want to specify some extra behavior here.
        pass
sys.stdout = Logger()   

此解决方案使用更多的计算能力,但可靠地将所有数据从标准输出保存到记录器文件中,并使用较少的内存。为了我的需要,我也将时间戳添加到self.log.write(message)中。效果很好。

答案 10 :(得分:0)

基于Brian Burns edited answer,我创建了一个易于调用的类:

class Logger(object):

    """
    Class to log output of the command line to a log file

    Usage:
    log = Logger('logfile.log')
    print("inside file")
    log.stop()
    print("outside file")
    log.start()
    print("inside again")
    log.stop()
    """

    def __init__(self, filename):
        self.filename = filename

    class Transcript:
        def __init__(self, filename):
            self.terminal = sys.stdout
            self.log = open(filename, "a")
        def __getattr__(self, attr):
            return getattr(self.terminal, attr)
        def write(self, message):
            self.terminal.write(message)
            self.log.write(message)
        def flush(self):
            pass

    def start(self):
        sys.stdout = self.Transcript(self.filename)

    def stop(self):
        sys.stdout.log.close()
        sys.stdout = sys.stdout.terminal

答案 11 :(得分:-2)

我试过了:

"""
Transcript - direct print output to a file, in addition to terminal.

Usage:
    import transcript
    transcript.start('logfile.log')
    print("inside file")
    transcript.stop()
    print("outside file")
"""

import sys

class Transcript(object):

    def __init__(self, filename):
        self.terminal = sys.stdout, sys.stderr
        self.logfile = open(filename, "a")

    def write(self, message):
        self.terminal.write(message)
        self.logfile.write(message)

    def flush(self):
        # this flush method is needed for python 3 compatibility.
        # this handles the flush command by doing nothing.
        # you might want to specify some extra behavior here.
        pass

def start(filename):
    """Start transcript, appending print output to given filename"""
    sys.stdout = Transcript(filename)

def stop():
    """Stop transcript and return print functionality to normal"""
    sys.stdout.logfile.close()
    sys.stdout = sys.stdout.terminal
    sys.stderr = sys.stderr.terminal

答案 12 :(得分:-6)

您可以使用>>将输出重定向到文件python与print rint的“chevron”语法,如docs

中所示

让我们看看,

fp=open('test.log','a')   # take file  object reference 
print >> fp , "hello world"            #use file object with in print statement.
print >> fp , "every thing will redirect to file "
fp.close()    #close the file 

签出文件test.log,你将获得数据 并在控制台上打印只需使用普通打印语句。