如何确定终端是否支持彩色显示?

32

我想修改一个程序,使其自动检测终端是否支持彩色功能,这样当我从不支持彩色的终端(比如在(X)Emacs的M-x shell中)运行该程序时,颜色会自动关闭。

我不想硬编码程序来检测TERM={emacs,dumb}。

我认为termcap/terminfo应该能够帮助解决这个问题,但到目前为止,我只能拼凑出这个(n)curses使用的代码片段,当找不到终端时会出现严重故障:

#include <stdlib.h>
#include <curses.h>

int main(void) {
 int colors=0;

 initscr();
 start_color();
 colors=has_colors() ? 1 : 0;
 endwin();

 printf(colors ? "YES\n" : "NO\n");

 exit(0);
}

也就是说,我得到了这个:

$ gcc -Wall -lncurses -o hep hep.c
$ echo $TERM
xterm
$ ./hep
YES
$ export TERM=dumb
$ ./hep           
NO
$ export TERM=emacs
$ ./hep            
Error opening terminal: emacs.
$ 

这是次优解决方案。


2
归根结底,你无法做到这一点,因为你无法确定终端所实现的CRT类型。 - anon
7
我对终端(类型)是否支持彩色功能感兴趣,而不是对来自CRT的光谱进行分析。 - asjo
3个回答

24

我的朋友向我介绍了tput(1),然后我就设计出了这个解决方案:

#!/bin/sh

# ack-wrapper - use tput to try and detect whether the terminal is
#               color-capable, and call ack-grep accordingly.

OPTION='--nocolor'

COLORS=$(tput colors 2> /dev/null)
if [ $? = 0 ] && [ $COLORS -gt 2 ]; then
    OPTION=''
fi

exec ack-grep $OPTION "$@"

这对我有用。不过,如果我有一种将其集成到 ack 的方式,那就太棒了。


2
请注意,ncurses的has_colors()执行比仅检查颜色数量更全面的测试,因为这不是终端信息中表达颜色支持的唯一方式。 - Chris Page
但是...但是...tput手册中没有提到"colors"命令。你的朋友怎么发现了这个好用的功能?! - Kingsley
1
tput(1)手册中写道:“tput [-Ttype] capname [parameters]”,因此“colors”是一个“capname”,即在terminfo数据库中定义的能力,而不是命令。因此,我猜要查看terminfo(5)以了解有哪些能力。 - asjo

10

你的方法基本正确,只是需要使用较低级别的curses函数setupterm而不是initscrsetupterm执行足够的初始化以读取terminfo数据,并且如果传递指向错误结果值的指针(最后一个参数),它将返回错误值而不是发出错误消息并退出(对于initscr的默认行为)。

#include <stdlib.h>
#include <curses.h>

int main(void) {
  char *term = getenv("TERM");

  int erret = 0;
  if (setupterm(NULL, 1, &erret) == ERR) {
    char *errmsg = "unknown error";
    switch (erret) {
    case 1: errmsg = "terminal is hardcopy, cannot be used for curses applications"; break;
    case 0: errmsg = "terminal could not be found, or not enough information for curses applications"; break;
    case -1: errmsg = "terminfo entry could not be found"; break;
    }
    printf("Color support for terminal \"%s\" unknown (error %d: %s).\n", term, erret, errmsg);
    exit(1);
  }

  bool colors = has_colors();

  printf("Terminal \"%s\" %s colors.\n", term, colors ? "has" : "does not have");

  return 0;
}

有关使用setupterm的其他信息,请参阅curs_terminfo(3X)手册页面(x-man-page://3x/curs_terminfo)和使用NCURSES编写程序


3
在我的 Mac OSX 机器上使用 C++,我还需要 #include <term.h>。 - Alec Jacobson
终端是硬拷贝,不能用于curses应用程序。我想知道是否有类似日志的终端,既不能擦除任何内容,也不能移动光标,但仍支持颜色,并且在某种程度上与ncurses有用?例如,许多CI环境都这样做。 - nponeccop
@AlecJacobson 这不仅适用于 C++,当然也适用于 C。 - Pryftan

5

查找终端类型的terminfo(5)条目,并检查Co(max_colors)条目。这就是终端支持的颜色数量。


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