程序如何决定是否有彩色输出?

Chr*_*ith 19 shell colors process terminal

当我从打印彩色输出(例如lsgcc)的终端执行命令时,将打印彩色输出。根据我的理解,该过程实际上是在输出ANSI 转义码,并且终端格式化颜色。

但是,如果我由另一个进程(比如自定义 C 应用程序)执行相同的命令并将输出重定向到应用程序自己的输出,这些颜色不会持续存在。

程序如何决定是否输出彩色格式的文本?是否有一些环境变量?

Ste*_*itt 26

大多数此类程序默认仅将颜色代码输出到终端;他们使用isatty(3). 通常有选项可以覆盖此行为:在所有情况下禁用颜色,或在所有情况下启用颜色。grep例如,对于 GNU ,--color=never禁用颜色并--color=always启用它们。

在 shell 中,您可以使用-t test运算符执行相同的测试:[ -t 1 ]仅当标准输出是终端时才会成功。

  • 已经在 http://unix.stackexchange.com/questions/249723/ 询问和回答,chris13523。顺便说一下,评论并不是真正的后续问题的地方。 (4认同)

Jde*_*eBP 16

是否有一些环境变量?

是的。它是TERM环境变量。这是因为有几件事被用作决策过程的一部分。

在这里很难概括,因为并非所有程序都同意一个决策流程图。事实上grep,在 M. Kitt 的回答中提到的GNU是一个很好的例子,它使用了一个有点不寻常的决策过程,结果出乎意料。因此,笼统地说:

  • 标准输出必须是终端设备,由 确定isatty()
  • 程序必须能够在 termcap/terminfo 数据库中查找终端类型的记录。
  • 所以因此必须一个终端类型来查找。该TERM环境变量必须存在和它的价值必须与数据库记录相匹配。
  • 因此必须有一个 terminfo/termcap 数据库。在子系统的某些实现中,可以使用TERMCAP环境变量指定 termcap 数据库的位置。所以在某些实现上有第二个环境变量。
  • termcap/terminfo 记录必须说明终端类型支持颜色。max_colorsterminfo 中有一个字段。它不是为实际上没有颜色功能的终端类型设置的。事实上,有一个 terminfo 约定,对于每个可着色的终端类型,都有另一条带有-m-mono附加到名称的记录,说明没有颜色功能。
  • termcap/terminfo 记录必须为程序提供改变颜色的方式。terminfo 中有set_a_foregroundset_a_background字段。

它比仅仅检查要复杂一些isatty()。它因以下几件事而变得更加复杂:

  • 一些应用程序添加命令行选项或配置标志来覆盖isatty()检查,以便程序始终从不假定它具有(可着色的)终端作为其输出。举些例子:
    • GNUls--color命令行选项。
    • BSDls着眼于CLICOLOR(它的缺失意味着从不)和CLICOLOR_FORCE(它的存在意味着总是)环境变量,并且还运行-G命令行选项。
  • 某些应用程序不使用 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

整数
should_colorize(无效)
{
  char const *t = getenv ("TERM");
  返回 t && strcmp (t, "dumb") != 0;
}

因此,即使您TERMxterm-mono,GNUgrep也会决定发出颜色,即使其他程序vim不会。

它的Win32 端口具有此代码,它在TERM环境变量存在或存在且其值与硬连线名称不匹配时启用着色dumb

整数
should_colorize(无效)
{
  char const *t = getenv ("TERM");
  返回 !(t && strcmp (t, "dumb") == 0);
}

GNUgrep的颜色问题

GNUgrep的着色实际上是臭名昭著的。因为它实际上并没有正确地构建终端输出,而只是在其输出的不同点指责一些硬连线控制序列,徒劳地希望这足够好,它实际上在某些情况下显示不正确的输出。

在这些情况下,它必须为终端右侧边缘的东西着色。正确执行终端输出的程序必须考虑自动右边距。 除了终端可能没有它们的轻微可能性(即auto_right_marginterminfo 中的字段)之外,具有自动右边距的终端的行为通常遵循挂起换行的 DEC VT 先例。GNUgrep没有考虑到这一点,天真地期望立即换行,它的彩色输出出错了。

彩色输出不是一件简单的事情。

进一步阅读

  • 据我了解,OP 正在询问重定向输出时的行为变化;`$TERM` 没有解释。(总的来说,您的回答很有趣,但我认为它没有解决问题......) (3认同)