当我从打印彩色输出的终端(例如ls
或gcc
)执行命令时,将打印彩色输出。据我了解,该过程实际上是输出ANSI 转义码,终端格式化颜色。
但是,如果我通过另一个进程(例如自定义 C 应用程序)执行相同的命令并将输出重定向到应用程序自己的输出,则这些颜色不会持续存在。
程序如何决定是否输出彩色格式的文本?是否有一些环境变量?
答案1
答案2
是否有一些环境变量?
是的。它是TERM
环境变量。这是因为有几件事被用作决策过程的一部分。
这里很难一概而论,因为并非所有程序都同意单一决策流程图。事实上,grep
M. Kitt 的回答中提到的 GNU 是一个异常值的好例子,它使用了一些不寻常的决策过程,并产生了意想不到的结果。因此,一般来说:
- 标准输出必须是终端设备,由 确定
isatty()
。 - 该程序必须能够在 termcap/terminfo 数据库中查找终端类型的记录。
- 所以因此必须有是要查找的终端类型。环境
TERM
变量必须存在并且其值必须与数据库记录匹配。 - 因此必须有一个 terminfo/termcap 数据库。在子系统的某些实现中,可以使用
TERMCAP
环境变量指定 termcap 数据库的位置。所以在一些实现上有一个第二环境变量。 - termcap/terminfo 记录必须声明终端类型支持颜色。
max_colors
terminfo 中有一个字段。它不是为实际上不具有颜色功能的终端类型设置的。事实上,有一个 terminfo 约定,对于每种可着色终端类型,都有另一个记录-m
或-mono
附加到名称,表明没有颜色功能。 - termcap/terminfo 记录必须提供程序改变颜色的方式。terminfo中有
set_a_foreground
和字段。set_a_background
这比仅仅检查要复杂一些isatty()
。它被制成更远由几件事复杂化:
- 一些应用程序添加命令行选项或配置标志来覆盖
isatty()
检查,以便程序总是或者绝不假设它有一个(可着色的)终端作为其输出。举些例子:- GNU
ls
有--color
命令行选项。 - BSD
ls
着眼于CLICOLOR
(它的缺席意味着绝不) 和CLICOLOR_FORCE
(其存在意义总是)环境变量,并且还支持-G
命令行选项。
- GNU
- 一些应用程序不使用 termcap/terminfo 并且对 的值有硬连线响应
TERM
。 - 并非所有终端都使用 ECMA-48 或 ISO 8613-6 SGR 序列来更改颜色,这些序列的名称稍有错误,即“ANSI 转义序列”。 termcap/terminfo 机制实际上旨在将应用程序与精确控制序列的直接知识隔离开来。 (此外,还有一种说法是没有人使用 ISO 8613-6 SGR 序列,因为每个人都同意这个错误使用分号作为 RGB 颜色 SGR 序列的分隔符。该标准实际上指定了冒号。)
如前所述,GNUgrep
实际上表现出了一些额外的复杂性。它不咨询 termcap/terminfo,硬连线要发出的控制序列,以及硬连线对TERM
环境变量的响应。
这它的 Linux/Unix 端口有这个代码TERM
,仅当环境变量存在且其值与硬连线名称不匹配时才启用着色dumb
:
整数 应该着色(空) { char const *t = getenv("TERM"); return t && strcmp(t, "哑巴") != 0; }
因此,即使您的TERM
是xterm-mono
,GNUgrep
也会决定发出颜色,即使其他程序(例如)vim
不会。
这它的Win32端口有这个代码,这可以在以下情况下实现着色TERM
环境变量才不是存在或者当它存在并且其值与硬连线名称不匹配时dumb
:
整数 应该着色(空) { char const *t = getenv("TERM"); 返回 ! (t && strcmp(t, "哑巴") == 0); }
GNUgrep
的颜色问题
GNUgrep
的彩色化实际上是臭名昭著的。因为它实际上并没有正确地构建终端输出,而只是在其输出中的各个点上指责一些硬连线控制序列,徒劳地希望这足够好,所以它实际上在某些情况下显示了不正确的输出。
在这些情况下,它必须对终端右侧边缘的某些内容进行着色。正确执行终端输出的程序必须考虑自动右边距。 此外终端可能没有它们(即auto_right_margin
terminfo 中的字段)的可能性很小,具有自动右边距的终端的行为通常遵循 DEC VT 先例待处理换行。 GNUgrep
没有考虑到这一点,天真地期待着立即换行,并且其彩色输出出错。
彩色输出并不是一件简单的事情。
进一步阅读
- 托马斯·E·迪基 (2016)。 ”
grep --color
不显示正确的输出”。xterm 常见问题解答。看不见的岛。 - 乔纳森·德博因·波拉德 (2016)。nosh 用户空间虚拟终端上手册页中的斜体和颜色。小吃包。
答案3
该unbuffer
命令来自预计包将第一个程序的输出与第二个程序的输入解耦。
你可以像这样使用它:
unbuffer myshellscript.sh | grep value
我一直将它与 ansible 和自制程序一起使用立方体脚本,以便我可以在终端上看到颜色输出,同时使日志文件保留正常(非彩色)输出。
unbuffer ansible-playbook myplaybook.yml | ctee /var/log/ansible/run-$( date "+%F" ).log