你喜欢颜色吗?--神秘的 ^[[ 字符
你是否曾经重定向过带有颜色的 curses 程序的输出,并想知道那些神秘的^[[符号是什么?你是否曾经尝试过在不使用 curses 的情况下使用 printf 命令来产生颜色? 如果你对其中任何一个问题的回答是肯定的,请继续阅读。本文试图解释在生成颜色的 curses 程序的输出中发现的神秘字符。 稍后,我们将扩展这个概念,仅使用 printf 命令来生成颜色。
在老式的电传打字机终端时代,终端远离计算机,并通过串行电缆连接到计算机。 可以通过向每个终端发送一系列字节来配置终端。 终端的所有功能都可以通过这些字节序列访问,这些字节序列通常称为转义序列,因为它们以转义 (0x1B) 字符开头。 即使在今天,通过 vt100 仿真,我们也可以向仿真器发送转义序列,这些序列对终端窗口具有相同的效果。 因此,为了打印颜色,我们只需回显一个控制代码。
首先,在您的控制台中输入以下内容
echo "^[[0;31;40mIn Color"
第一个字符是转义字符,它看起来像两个字符,^ 和 [。 为了能够打印这个,你必须按 CTRL+V,然后按 ESC 键。 所有其他字符都是正常的打印字符,所以你会看到字符串彩色以红色显示。 类型会保持这种颜色,直到您通过输入以下内容恢复为止
echo "^[[0;37;40m"
正如您所看到的,在控制台或 xterm 中设置和重置颜色很容易。 有无数的转义序列可供使用,您可以使用它们做很多事情,包括移动光标和重置终端。
现在,我解释用于生成颜色的转义序列。 要打印或回显到终端的序列是
<ESC>[{attr};{fg};{bg}m
第一个字符是 ESC,它必须通过在 Linux 控制台或 xterm、konsole、kvt 等中按 CTRL+V,然后按 ESC 来输入。 顺便说一句,CTRL+V ESC 也是在 Vim 文档中嵌入 Esc 字符的组合。 然后,{attr}、{fg} 和 {bg} 必须替换为正确的值才能达到相应的效果。 attr 是属性,例如闪烁或下划线文本,而 fg 和 bg 分别是前景色和背景色。 您不必在数字周围加上大括号; 只需写数字就足够了。
{attr} 需要是以下之一
0 重置所有属性(返回正常模式)
1 高亮(通常打开粗体)
2 变暗
3 下划线
5 闪烁
7 反显
8 隐藏
{fg} 需要是以下之一
30 黑色
31 红色
32 绿色
33 黄色
34 蓝色
35 洋红色
36 青色
37 白色
{bg} 需要是以下之一
40 黑色
41 红色
42 绿色
43 黄色
44 蓝色
45 洋红色
46 青色
47 白色
因此,要获得带有蓝色前景和绿色背景的闪烁行,组合应该是
echo "^[[5;34;42mIn color"
这实际上非常难看。 所以,用以下命令恢复
echo "^[0;37;40m"
如果你想在 C 程序中使用这种代码颜色和属性功能怎么办? 嗯,这很简单。 在你 printf 任何东西之前,打印转义序列以用所需的颜色生成它。 我编写了一个小的例程 textcolor(),它可以自动为你完成此操作。 你可以在你的 C 程序中使用它,以及 #define 常量。
|textcolor()| #include <stdio.h> #define RESET 0 #define BRIGHT 1 #define DIM 2 #define UNDERLINE 3 #define BLINK 4 #define REVERSE 7 #define HIDDEN 8 #define BLACK 0 #define RED 1 #define GREEN 2 #define YELLOW 3 #define BLUE 4 #define MAGENTA 5 #define CYAN 6 #define WHITE 7 void textcolor(int attr, int fg, int bg); int main() { textcolor(BRIGHT, RED, BLACK); printf("In color\n"); textcolor(RESET, WHITE, BLACK); return 0; } void textcolor(int attr, int fg, int bg) { char command[13]; /* Command is the control command to the terminal */ sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40); printf("%s", command); }
textcolor() 程序是根据 Turbo C API 函数建模的。 你调用该函数来设置颜色,然后用以下命令打印它sprintf(),这是一个在 Turbo C 中用于生成彩色控制台输出的函数。
以下程序要求用户使用属性和颜色,然后以这些颜色和属性显示文本字符串。 我通常使用它来为我的 GUI 找到最佳的颜色组合。
#include <stdio.h> #define RESET 0 #define BRIGHT 1 #define DIM 2 #define UNDERLINE 3 #define BLINK 4 #define REVERSE 7 #define HIDDEN 8 #define BLACK 0 #define RED 1 #define GREEN 2 #define YELLOW 3 #define BLUE 4 #define MAGENTA 5 #define CYAN 6 #define WHITE 7 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) char *attrs[] = {"NORMAL", "BRIGHT", "DIM", "UNDERLINE", "BLINK", "REVERSE", "HIDDEN", "EXIT"}; char *colors[] = {"BLACK", "RED", "GREEN", "YELLOW", "BLUE", "MAGENTA", "CYAN", "WHITE", "EXIT"}; void textcolor(int attr, int fg, int bg); int print_menu(char *array[], int n_options, char *title); int main() { int attr, fg, bg; int attr_size, colors_size; attr_size = ARRAY_SIZE(attrs); colors_size = ARRAY_SIZE(colors); while(1) { printf("\n"); attr = print_menu(attrs, attr_size, "Choose the attr you want:"); if(attr == attr_size - 1) break; fg = print_menu(colors, colors_size, "Choose the foreground you want:"); if(attr == colors_size - 1) break; bg = print_menu(colors, colors_size, "Choose the background you want:"); if(attr == colors_size - 1) break; printf("\n"); textcolor(attr, fg, bg); printf("This is what you get if you use the combination %s attribute %s foreground and %s background", attrs[attr], colors[fg], colors[bg]); textcolor(RESET, WHITE, BLACK); system("clear"); } return 0; } int print_menu(char *array[], int n_options, char *title) { int choice, i; for(i = 0;i < n_options; ++i) printf("%d.%s\n", i, array[i]); printf("%s", title); scanf("%d", &choice); return choice; } void textcolor(int attr, int fg, int bg) { char command[13]; /* Command is the control command to the terminal */ sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40); printf("%s", command); }
那么,问题是什么呢? 如果为文本生成颜色和属性如此容易,为什么人们要浪费时间用 curses 编写庞大的程序,而 curses 又以复杂的方式查询 terminfo 呢? 正如我们所知,那里有很多功能很少的终端。 其他终端不识别这些转义代码,或者需要输入不同的代码才能达到相同的效果。 因此,如果你想要一个可以在各种终端上以相同或减少的功能运行的可移植程序,你应该使用 curses。 Curses 使用 terminfo 来查找正确的代码,以在各种终端上完成这些类型的任务。 Terminfo 是一个大型数据库,其中包含有关不同终端的各种功能的信息。
但是,如果你只想编写一个在 Linux 控制台或 xterm 窗口中生成颜色的程序,你可以轻松地使用上面的转义序列来做到这一点。 Linux 控制台主要模拟 vt100,因此它可以识别这些转义序列。
但是,有一种方法可以查询 terminfo 数据库以获取你需要的信息,并自己完成工作。 tput 是查询数据库并执行你指定的功能的命令。 setf 和 setb 这两个功能对于设置前景色和背景色很有用。 例如,使用以下命令将前景色设置为红色,背景色设置为绿色
tput setf 4 # tput setf {fg color number} tput setb 2 # tput setb {bg color number}
这些命令可以在任何你想要的 shell 脚本中使用。 有关 tput 的其他功能,请参阅 tput 手册页。 terminfo 手册页包含大量有关终端功能、如何获取和设置其值等信息。 有两个 terminfo 手册页man 5 terminfo描述 terminfo 数据库,以及man 3ncurses terminfo描述使用该数据库的 C 函数。
以下是要作为参数传递给的数字tput setf和tput setb及其对应的颜色
0 黑色
1 红色
2 绿色
3 黄色
4 蓝色
5 洋红色
6 青色
7 白色
版权所有 (c) 2001, Pradeep Padala。 最初发表于 Linux Gazette 第 65 期。 版权所有 (c) 2001, Specialized Systems Consultants, Inc.
Pradeep Padala 拥有计算机科学与工程学士学位(相当于理学学士)。 他的兴趣包括解谜和玩棋盘游戏。