development

스크립팅을 사용하여 stdout을 파일과 콘솔 모두로 리디렉션하는 방법은 무엇입니까?

big-blog 2020. 12. 3. 08:07
반응형

스크립팅을 사용하여 stdout을 파일과 콘솔 모두로 리디렉션하는 방법은 무엇입니까?


파이썬 스크립트를 실행하고 텍스트 파일의 출력을 캡처하고 콘솔에 표시하고 싶습니다.

파이썬 스크립트 자체의 속성으로 지정하고 싶습니다. echo "hello world" | tee test.txt매번 명령 프롬프트에서 명령 을 사용하지 마십시오 .

스크립트 내에서 시도했습니다.

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

그러나 이것은 화면에 stdout 출력을 표시하지 않습니다.

로깅 모듈에 대해 들었지만 해당 모듈을 사용하여 작업을 수행하는 데 운이 없었습니다.


Python 파일을 실행하는 동안 셸 리디렉션을 사용할 수 있습니다.

python foo_bar.py > file

이것은 파이썬 소스에서 stdout에 인쇄되는 모든 결과를 로그 파일에 파일로 기록합니다.

또는 스크립트 내에서 로깅을 원하는 경우 :

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과 logfile 모두에 "Hello"를 기록합니다.


출력을 콘솔과 텍스트 파일로 동시에 리디렉션하는 방법이 있습니다.

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)

로깅 모듈을 사용하여 앱 디버그 및 팔로우

다음은 파일 및 콘솔 / stdout에 로그인하는 방법입니다.

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


더 쉬운 해결책을 고안했습니다. 파일이나 화면 또는 둘 다에 인쇄 할 함수를 정의하기 만하면됩니다. 아래 예에서는 사용자가 출력 파일 이름을 인수로 입력하도록 허용하지만 필수는 아닙니다.

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)입니다.


Amith Koujalgi의 답변을 기반으로 로깅에 사용할 수있는 간단한 모듈은 다음과 같습니다.

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

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.

Tee클래스는 IPython.utils.io원하는 것을 수행하지만-문 에서 호출하는 데 필요한 __enter____exit__메서드가 with없습니다. 그것들은 contextlib.closing.


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.spawnsubprocess.Popen기반 솔루션 의 장점은 sys.stdout예를 들어 스크립트가 stdout / stderr에서 출력을 생성 할 수있는 다른 프로세스를 시작하는 경우 파일 설명자 수준에서 출력을 캡처 할 수 있다는 것입니다. 관련 질문에 대한 내 대답을 참조하십시오 : stdout을 Python의 파일로 리디렉션합니까?


다음은 콘솔에 인쇄하고 동일한 출력을 파일에 쓰는 간단한 컨텍스트 관리자입니다. 또한 파일에 모든 예외를 기록합니다.

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

여기에서 몇 가지 솔루션을 시도했지만 파일과 콘솔에 동시에 쓰는 솔루션을 찾지 못했습니다. 그래서 여기에 내가 한 일이 있습니다 (이 답변을 바탕으로)

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

This solution uses more computing power, but reliably saves all of the data from stdout into logger file and uses less memeory. For my needs I've added time stamp into self.log.write(message) aswell. Works great.


I tried this:

"""
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

you can redirect the output to a file by using >> python with print rint's "chevron" syntax as indicated in the docs

let see,

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 

checkout the file test.log you will have the data and to print on console just use plain print statement .

참고URL : https://stackoverflow.com/questions/14906764/how-to-redirect-stdout-to-both-file-and-console-with-scripting

반응형