在Windows上使用tee时如何保留python colorama颜色输出
在我的Windows 10场景中,我希望将任意python控制台输出(在Windows上使用tee时如何保留python colorama颜色输出,python,windows,tee,colorama,Python,Windows,Tee,Colorama,在我的Windows 10场景中,我希望将任意python控制台输出(print(),sys.exit(),等等)打印到控制台和日志文件中。我无法控制代码的某些部分(外部python包),因此无法使用某些专用的日志机制 经过一些研究,我在UnxUtils中找到了工具tee.exe,它几乎按照我想要的方式完成了这个任务 我的问题是保留python的colorama包生成的颜色。有没有办法做到这一点?目前,tee.exe会去除颜色 我正在寻找的答案不必依赖于tee.exe,它只是我最接近真正解决方案
print()
,sys.exit()
,等等)打印到控制台和日志文件中。我无法控制代码的某些部分(外部python包),因此无法使用某些专用的日志机制
经过一些研究,我在UnxUtils中找到了工具tee.exe,它几乎按照我想要的方式完成了这个任务
我的问题是保留python的colorama包生成的颜色。有没有办法做到这一点?目前,tee.exe会去除颜色
我正在寻找的答案不必依赖于tee.exe,它只是我最接近真正解决方案的地方。我要找的应该是:
- 任何命令行输出都显示在命令行和日志文件中(STOUT和STDERR)
- 输出实时显示在命令行上。如果日志文件也是如此,则可获得额外点数
- 颜色保留在命令行上。如果日志文件不包含任何与颜色相关的工件,则可获得额外点数
tee.exe
没有错。相反,colorama通过设计去除了颜色控制的ANSI字符,因此当通过tee.exe
时,颜色会丢失
从colorama手册:
Colorama通过包装stdout、剥离它找到的ANSI序列(在输出中显示为gobbledygook)并将它们转换为适当的win32调用来修改终端的状态,在Windows上也可以实现这一点
Colorama的init()
函数提供参数strip
,如果False
,则会导致Colorama不去除ANSI字符。这反过来又允许编写一个自定义的tee.py
,其作用与tee.exe
相同,如下面user@martineau所述。在其中,我们可以调用colorama并正确处理颜色
这可能是一个可行的解决方案,但它仍然有一个缺点,那就是在我的原始python代码中,我必须用init(strip=False)
替换所有coloramainit()
调用,如果调用代码时没有通过tee.py
重定向,那么反过来会导致ANSI字符出现在输出中
这实际上可能是我们能找到的最接近于正确解决方案的地方。如果有人能提供其他想法,我洗耳恭听,但我担心机会渺茫。我不知道它在
colorama
方面会如何工作,但在对我在网上找到的几个tee
Windows实用程序不满意之后,我最终用Python(3.x)编写了自己的实用程序
您可能需要修改它以满足您自己的需要,但这应该是一个良好的开端
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)
“”“
将标准输入复制到指定文件的标准输出(屏幕)*和*。
"""
导入文件输入
导入操作系统
从pathlib导入路径
导入系统
显示完整路径=错误
除法器=真
DIV_CH=“”
如果len(sys.argv)!=2:
raise SystemExit('用法:mytee')
尝试:
inp=fileinput.input(())#从标准输入读取。
路径=路径(sys.argv[1])
stdout_write=sys.stdout.write
stdout\u flush=sys.stdout.flush
#假定.py与输出文件位于同一目录中。
脚本=(f'{path.parent/path.stem}{path.suffix}',如果SHOW_FULL_path else
f'{path.stem}{path.suffix}')
将open(路径“w”)作为输出:#写入指定文件。
outp_write=outp.write
outp_flush=outp.flush
def写入(行):
标准输出写入(行)
输出写入(行)
def writeln(行):
写入(第+'\n'行)
banner=f'{script}'(如果脚本else中的''-[{script}]-'
writeln(f'{banner}')
如果分隔器:
书写(f'{DIV_CH*len(banner)}')
对于inp中的行:
写(行)
如果分隔器:
书写(f'{DIV_CH*len(banner)}')
writeln('-[done]-')
最后:
inp.close()#不确定这是否真的有必要。
系统出口(0)
这是个很酷的主意!从我用你的代码进行的测试中,它似乎也去除了颜色信息。很可能colorama在打印时会消耗颜色信息,因此零件永远不会传递给stout。也许我可以在python中找到另一种方法来捕获这些数据。谢谢你的主意!Windows的管道命令,|
,可能是剥离颜色信息的原因。根据您的解决方案,可能有一种方法。init()具有可选属性“strip”。如果设置为False,它将保留控制字符。因此,如果我在代码中添加一个colorama.init(),并在我的代码中用colorama.init(strip=False)替换colorama.init(),那么它就可以工作了。这仍然不理想,因为我必须修改代码以适应变化,但这是朝着正确方向迈出的一步。塞尔诺:很高兴听到我的“一次性”实用程序被证明对其他人有用。请随意发布您自己的答案,其中包含支持colorama
的更改,以供其他人使用。简单地问一个问题:您假设tee
剥离ANSI序列,但您实际测试过吗colorama
本身是终端感知的:“如果在Windows上或如果输出被重定向(不是tty),则默认行为是剥离。”@usr2564301。也许我说得不对。我认为tee
不会剥离ANSI序列,但事实上,colorama确实如此。见我对马蒂诺回答的评论。我本想把这些信息整合到原来的帖子中,但还没有开始。解决方案可能是使用colorama的strip
argum
@echo off
python teetest.py 2>&1 | tee log.txt
pause
Test
2nd Test
Color Test
Error_Test
"""
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)