102

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

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

在我尝试的脚本中:

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

但这不会在屏幕上显示标准输出。

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

4

14 回答 14

152

您可以在执行 Python 文件时使用 shell 重定向:

python foo_bar.py > file

这会将打印在标准输出上的所有结果从 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"

这会将“Hello”写入标准输出和日志文件。

于 2013-02-16T04:00:38.877 回答
23

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

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)
于 2013-02-16T05:49:11.130 回答
16

使用日志模块来调试和关注你的应用

这是我设法记录到文件和控制台/标准输出的方法

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

于 2016-07-15T11:22:20.297 回答
14

根据Amith Koujalgi 的回答,这是一个可用于记录的简单模块 -

成绩单.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
于 2017-01-05T03:59:16.347 回答
9

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

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

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

在此之后,将一行打印到文件和/或屏幕所需的只是:printing(Line_to_be_printed)

于 2016-01-07T01:58:21.647 回答
8
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.

in 中的TeeIPython.utils.io做你想做的事,但它缺少在-statement中调用它所需的__enter__和方法。这些是由添加的。__exit__withcontextlib.closing

于 2018-03-09T15:33:06.033 回答
5

我在这里尝试了一些解决方案,但没有找到同时写入文件和控制台的解决方案。所以这就是我所做的(基于这个答案)

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) 中添加了时间戳。效果很好。

于 2019-08-11T16:44:08.787 回答
5

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

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")
于 2019-07-12T14:09:59.930 回答
4

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

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()
于 2021-01-26T18:47:54.837 回答
1

要将输出重定向到文件和终端而不修改 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()函数替换它,但它提供普通管道而不是伪终端——它可能会改变某些程序的行为。

与替换为类文件对象相比,基于 和 - 的解决方案pty.spawn的优势在于,它们可以在文件描述符级别捕获输出,例如,如果脚本启动其他进程,这些进程也可以在 stdout/stderr 上产生输出。请参阅我对相关问题的回答:将标准输出重定向到 Python 中的文件?subprocess.Popensys.stdout

于 2014-09-10T03:31:24.677 回答
0

根据@Arnold Suiza 的回答,这是一个您可以在开始时运行一次的函数,之后所有函数都将立即打印到标准输出和文件:

def print_to_file(filename):
    orig_stdout = sys.stdout  # capture original state of stdout

    class Unbuffered:
        def __init__(self, filename):
            self.stream = orig_stdout
            self.te = open(filename,'w')  # File where you need to keep the logs

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

    sys.stdout=Unbuffered(filename)

现在只需print_to_file('log.txt')在程序开始时运行,您就可以开始了!

于 2021-08-24T02:37:07.753 回答
0

基于Brian Burns 编辑的答案,我创建了一个更容易调用的类:

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
于 2020-02-24T12:37:21.757 回答
-3

我试过这个:

"""
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
于 2017-06-06T14:54:06.973 回答
-6

您可以使用 >> python 和 print rint 的“chevron”语法将输出重定向到文件中,如文档中所示

让我们看看,

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 您将拥有数据并在控制台上打印只需使用普通打印语句。

于 2013-02-16T05:51:37.613 回答