简体   繁体   English

在 Windows 上使用 tee 时如何保留 python colorama 颜色输出

[英]How to preserve python colorama color output when using tee on Windows

In my Windows 10 scenario, I want to print arbitrary python console output ( print() , sys.exit() , etc) both to console and a log file.在我的 Windows 10 场景中,我想将任意 python 控制台输出( print()sys.exit()等) print()到控制台和日志文件。 I don't have control over some parts of the code (external python packages), so I cannot use some dedicated logging mechanism.我无法控制代码的某些部分(外部 python 包),所以我不能使用一些专用的日志记录机制。

After some research I found the tool tee.exe in UnxUtils which does this task almost the way I want.经过一番研究,我在 UnxUtils 中找到了工具tee.exe ,它几乎按照我想要的方式完成了这项任务。

My problem is to preserve color as generated by python's colorama package.我的问题是保留由 python 的colorama包生成的颜色。 Is there any way to accomplish that?有没有办法做到这一点? Currently, tee.exe strips away the color.目前,tee.exe 会去除颜色。

The answer I am looking does not have to rely on tee.exe, it's just the closest I got to a real solution.我正在寻找的答案不必依赖于 tee.exe,它只是我最接近真正解决方案的方法。 What I am looking for should do the following:我正在寻找的应该执行以下操作:

  • any command line output appears both in the command line and the log file (both STOUT and STDERR)任何命令行输出都出现在命令行和日志文件中(STOUT 和 STDERR)
  • the output appears on the command line in real time.输出实时显示在命令行上。 Bonus points if this is also true for the log file.如果日志文件也是如此,则加分。
  • color is preserved on the command line.颜色保留在命令行上。 Bonus points if the log file does not contain any color-related artifacts.如果日志文件不包含任何与颜色相关的工件,则加分。

What I have so far is this:到目前为止,我所拥有的是:

Python file teetest.py : Python 文件teetest.py

import sys
import colorama

print("Test")
print("2nd Test")

colorama.init(autoreset=True)
print(colorama.Fore.RED + 'Color Test')
colorama.deinit(autoreset=True)

sys.exit("Error_Test")

Batch file teetest.bat :批处理文件teetest.bat

@echo off
python teetest.py 2>&1 | tee log.txt
pause

My output looks like this (command line and log file are identical, no color):我的输出看起来像这样(命令行和日志文件是相同的,没有颜色):

Test
2nd Test
Color Test
Error_Test

The solution I am looking for will print the above to the command line so the words Color Test are red.我正在寻找的解决方案将上面的内容打印到命令行,因此颜色测试字样是红色的。

Edit:编辑:

It seems that tee.exe is not at fault.似乎tee.exe没有错。 Instead, colorama strips away the ANSI characters for color control by design, so the color is lost when passed through tee.exe .相反,colorama 通过设计去除了用于颜色控制的 ANSI 字符,因此在通过tee.exe时颜色会丢失。

From the colorama manual:来自colorama手册:

Colorama makes this work on Windows, too, by wrapping stdout, stripping ANSI sequences it finds (which would appear as gobbledygook in the output), and converting them into the appropriate win32 calls to modify the state of the terminal. Colorama 也通过包装 stdout、剥离它找到的 ANSI 序列(在输出中显示为 gobbledygook)并将它们转换为适当的 win32 调用来修改终端的状态,从而在 Windows 上实现此功能。

Colorama's init() function offers the parameter strip , which if False , does cause colorama to not strip away the ANSI characters. Colorama 的init()函数提供参数strip ,如果为False ,则确实会导致 colorama 不剥离 ANSI 字符。 This in turn allows to write a custom tee.py that does the same as tee.exe , as outlined by user @martineau below.这反过来又允许编写与tee.py相同的自定义tee.exe ,如下面用户@martineau 所述。 In it, we can call colorama and handle the color properly.在其中,我们可以调用 colorama 并正确处理颜色。

This might be a workable solution, but it still has the downside that I would have to replace all colorama init() calls with init(strip=False) in my original python code and that in turn would cause ANSI characters to appear in the output if the code was called without redirecting through tee.py .这可能是一个可行的解决方案,但它仍然有缺点,我必须在我的原始 python 代码中用init(strip=False)替换所有 colorama init()调用,这反过来会导致 ANSI 字符出现在输出中如果在没有通过tee.py重定向的情况下调用代码。

This might actually be the closest we can get to a proper solution here.这实际上可能是我们在这里最接近正确解决方案的方法。 If anyone can offer other ideas, I'm all ears but I fear chances are slim.如果有人可以提供其他想法,我全神贯注,但我担心机会很小。

I don't know how it will work with respect to colorama , but after being unsatisfied with several tee utilities for Windows that I found online, I ended up writing my own in Python (3.x).我不知道它在colorama方面将如何工作,但是在对我在网上找到的几个适用于 Windows 的tee实用程序不满意之后,我最终用 Python (3.x) 编写了自己的。

You may have to modify it to suit your own needs, but it should be a good start.您可能需要修改它以满足您自己的需要,但这应该是一个好的开始。

mytee.py : mytee.py :

"""
    Copies stdin to stdout (screen) *and* the specified file.
"""
import fileinput
import os
from pathlib import Path
import sys

SHOW_FULL_PATH = False
DIVIDER = True
DIV_CH = ' '

if len(sys.argv) != 2:
    raise SystemExit('Usage: mytee <filepath>')

try:
    inp = fileinput.input(())  # Read from stdin.
    path = Path(sys.argv[1])
    stdout_write = sys.stdout.write
    stdout_flush = sys.stdout.flush
    # Assumes .py in same dir as output file.
    script = (f'{path.parent/path.stem}{path.suffix}' if SHOW_FULL_PATH else
              f'{path.stem}{path.suffix}')

    with open(path, 'w') as outp:  # Write to specified file.
        outp_write = outp.write
        outp_flush = outp.flush

        def write(line):
            stdout_write(line)
            outp_write(line)

        def writeln(line):
            write(line + '\n')

        banner = f'"{script}"' if ' ' in script else f'-[{script}]-'
        writeln(f'{banner}')
        if DIVIDER:
            writeln(f'{DIV_CH * len(banner)}')
        for line in inp:
            write(line)
        if DIVIDER:
            writeln(f'{DIV_CH * len(banner)}')
        writeln('-[done]-')
finally:
    inp.close()  # Not sure this is really necessary.

sys.exit(0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM