在xterm中读取当前文本颜色

33

我正在编写各种实用工具,并且很喜欢彩色文本。没有什么花哨的,只是使用转义序列。我创建了一个简单的类,其中包含pprint (msg,color)函数。在找到代码here后,我很容易就让它正常工作了。

我的问题是我应该能够在打印后关闭颜色。例如,假设用户运行我的程序将几乎所有内容都以默认终端颜色打印,但出现错误,我想以红色打印错误。我在我的错误消息前加上 '\033[0;32m',消息是红色的。不幸的是,在更改之前,所有文本都是红色的。因为我知道消息应该是什么颜色,所以在程序运行时通常没问题。但是,颜色在我的程序结束后仍然保留。基本上,我想在程序启动时读取当前颜色,并在完成后还原它。就像脚本在退出时恢复pwd一样。

如何读取当前的转义序列?

系统: Red Hat 5.x Bash Python 2.3

感谢您的帮助。

4个回答

155

不要使用混淆的转义序列,可以使用 tput 工具代替。这是从我的 ~/.bashrc 文件中摘录的用于我的 PS1 提示符的代码:

BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
LIME_YELLOW=$(tput setaf 190)
POWDER_BLUE=$(tput setaf 153)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
BRIGHT=$(tput bold)
NORMAL=$(tput sgr0)
BLINK=$(tput blink)
REVERSE=$(tput smso)
UNDERLINE=$(tput smul)
为了重置颜色信息,使得后续文本以正常终端颜色显示,您需要在末尾添加${NORMAL},如下所示: echo "${RED}这是红色 ${NORMAL}这是普通的"

4
有用,但与我阅读的问题无关。用户在运行脚本之前不一定将终端设置为“正常”颜色,并且可能不希望脚本在运行后设置“正常”颜色。 - Karl Knechtel
谢谢你的回答,但Karl是正确的。我需要在Python脚本中设置它,所以虽然BASH别名可以工作,但它们似乎不是最好的解决方案。并不是转义序列更好... - fandingo
又来一个依赖项.. 这是我最不需要的事情。 - Dan Bechard
2
它在Windows上并不普及。我使用.sh脚本与Git Bash结合使用,有许多有用的Linux工具我无法方便地使用。其中之一是tput。当然,我可以运行cygwin,甚至只需将tput可执行文件放入我的Git目录中,但是当转义序列完美地工作时,这似乎过于复杂。说实话,对我来说,$(tput setaf 6)并不比'\e[00;36m'更难懂。它们还会在初始化颜色常量时分叉另一个进程15次。 - Dan Bechard
1
@Dan,你不能一直取悦所有人,18个人中有1个已经很不错了。 - SiegeX
显示剩余2条评论

6

实际上,对于xterm兼容终端,这是可能的。

例如,xtermcontrol 使用OSC 10控制序列检索默认前景/背景颜色。自2002年以来,它已在xterm中记录。

对于其他终端:

  • 在RHEL 5中,“终端”程序是gnome-terminal 2.16.0;该版本不识别 OSC 10 (使用等效的CentOS 5进行测试)。
  • 这个问题是在2010年提出的,涉及到红帽企业版,如果说有什么区别的话,那就是更新比Debian慢。
  • 随着时间的推移,在Debian 7上的gnome-terminal 3.4.1.1(2012年初)也没有识别控制序列。
  • 最后,在Debian 8上使用3.14.1(2014年末),该功能被识别。
  • CentOS 7的gnome-terminal 3.14.3识别该控制序列。

如果想知道何时添加该功能,请记住VTE的开发人员不编写文档。 因此...研究git日志显示

commit 1b8c6b1aac587b79476a60a5830385abc939430d 
Author: Egmont Koblinger <egmont@gmail.com> 
Date:   Wed Jan 22 00:13:51 2014 +0100

    emulation: Add support for OSC 1?1[017] (fg, bg, highlight colors)

    https://bugzilla.gnome.org/show_bug.cgi?id=567444

另一方面,“默认”颜色与“当前”颜色不同。自1999年以来,用户已经能够使用xterm进行此操作(请参阅补丁#93),使用DECRQSS控制序列。也就是说,将终端设置为原始模式并执行类似以下命令的操作。
printf '\033P$m\033\\'

我会尽力帮忙翻译。以下是您需要翻译的内容:

将其回复字符串填充SGR参数。

如果使用SGR设置颜色,则这些代码将成为回复的一部分,例如。

\033P1$r0;33m\033\\

用编码为33的数字表示前景色号码3。

你可以在此停止(因为你可以提取这些参数并重复使用它们以后再设置终端到相同状态),但是使用OSC 4可以获取实际的RGB颜色。你需要使用SGR序列中的颜色编号,并发送类似于以下内容:

printf '\033]4;3;?\033\\'

使用xterm肯定是可行的。下一个xterm更新将会有一个关于DECRQSS的演示/测试脚本。

对于其他程序,你需要更多时间:

  • xtermcontrol的开发者忽略了DECRQSS(它没有设置/获取SGR代码的功能)。

  • VTE的开发人员在bug报告中复制xterm功能;VTE源代码中没有提到DECRQSS。它的git日志在2009年提到了OSC 4,但实现不完整(它只允许设置颜色,而不能获取颜色)。


4
我不相信这是可能的,即使可以,也不太可能是可移植的。你能做的最好的办法是发送sgr0,它将所有属性重置为默认值(而非先前的值)。在xterms上,sgr0Esc[m。如果您想重置颜色而不影响其他属性,请发送op,在xterms上,它是Esc[39;49m

这些代码不应硬编码。您应该使用terminfo、termcap或[n]curses。


谢谢您的回复。我查看了您提供的链接,但没有找到与sgr0或颜色相关的内容。您能否详细说明或提供相关章节?重置sgr0似乎完美地解决了问题,除非有强制的可移植性原因,否则我将在短期内坚持使用它。未来的计划是使用与terminfo / termcap或curses直接交互的东西,但需要一段时间才能添加这些模块。 - fandingo
1
@fandingo:这个链接的重点是,许多声称兼容xterm的终端仿真器并不支持xterm所支持的许多控制序列,从而影响了更为晦涩的功能的可移植性。您可以在man 5 terminfo中了解更多关于terminfo的信息,以及在此处了解有关xterm控制序列的信息。 - Dennis Williamson

4
RED = 31
GREEN = 32
ESCAPE = '%s[' % chr(27)
RESET = '%s0m' % ESCAPE
FORMAT = '1;%dm'

def colorize(text, color):
    return ESCAPE + (FORMAT % (color, )) + text + RESET

这个函数将返回一个带有颜色的字符串,打印出来后终端会自动重置。


转换序列存在问题,当使用它进行打印时,我可以看到文本和所有的转义序列。 - fandingo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接