Linux终端下打印带颜色的信息

很早之前在学习Makefile的时候,对linux的shell字体颜色有一点点研究。在使用ffmpeg工具时,也看到带有不同的颜色的信息输出,比如红色表示错误信息。现在,重新用代码来实现输出不同的颜色的打印信息。

打印不同颜色的核心格式为:[{attr};{fg};{bg}m。其中,在ascii中也用“^[”表示,在研究uboot时也顺便学习了一下。在代码中,如用八进制,写作\033,如用十六进制则写作\x1b(参见下面的代码)。
attr表示显示字体的属性,如加粗、下划线、闪烁等。值如下:

1
2
3
4
5
6
7
0       Reset All Attributes (return to normal mode)
1       Bright (Usually turns on BOLD)
2       Dim
3       Underline
5       Blink
7       Reverse
8       Hidden

fg是前景颜色,即字体颜色,如红色、黄色等,值如下:

1
2
3
4
5
6
7
8
30      Black
31      Red
32      Green
33      Yellow
34      Blue
35      Magenta
36      Cyan
37      White

bg是背景颜色,值如下:

1
2
3
4
5
6
7
8
40      Black
41      Red
42      Green
43      Yellow
44      Blue
45      Magenta
46      Cyan
47      White

前景色和背景色索引值相同,只是前景色是30开始,背景色是40开始。
通过上面3个字段的组合可以得到表现不同的信息。比如警告信息我用黄色字体表示,错误用红色字体表示。如图:

各颜色效果图:

注意,如果用secureCRT之类的工具连接linux,则要在会话选项中将终端类型选择为linux,而不是默认的vt100,否则颜色将无效。 完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
设置打印信息的字体颜色,在终端类型为"linux"下测试通过。
格式:<ESC>[{attr};{fg}此处为打印信息<ESC>[{gb}m
另一种格式
<ESC>[{attr};{fg};{bg}m
此处为打印信息
<ESC>[RESET;{fg};{bg}m <--此处是复位属性,否则会影响后面的输出信息
0x1b为转义字符"^[" {attr}为字体属性 {fg}为字体颜色 "[0m"为黑色背景
前景色(字体)
30 Black
31 Red
32 Green
33 Yellow
34 Blue
35 Magenta
36 Cyan
37 White
背景色
bg:
40 Black
41 Red
42 Green
43 Yellow
44 Blue
45 Magenta
46 Cyan
47 White
注:两种颜色索引值一致,一个是30开始,一个是40开始
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#define RESET 0
#define BRIGHT 1
#define DIM 2
#define UNDERLINE 4
#define BLINK 5
#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)
{
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);
}

void color_test(void)
{
textcolor(BRIGHT, RED, GREEN);
printf("hello %d\n", 250);
textcolor(RESET, WHITE, BLACK);
}

//==================================
#define BUG_LEN 1024
void my_vprint(char* fmt, va_list va_args)
{
char buffer[BUG_LEN] = {0};
vsnprintf(buffer, BUG_LEN-1, fmt, va_args);
printf("%s", buffer);
}

// 不使用背景色
void _print_color(int attr, int color, const char* fmt,...)
{
char buffer[BUG_LEN] = {0};
va_list marker;
va_start(marker, fmt);

// 背景色为0时,不影响后面的信息,其它值会影响
snprintf(buffer, BUG_LEN-1, "\x1b[%d;%dm%s\x1b[0m", attr, color+30, fmt);
my_vprint(buffer, marker); // 一定要这个函数才能使用可变参数
va_end(marker);
}

// 要用宏,用函数的话,不能用可变参数
#define print_color(attr, color, fmt,...) _print_color(attr, color, fmt, ##__VA_ARGS__)
#define warn(fmt, ...) _print_color(BRIGHT, YELLOW, fmt, ##__VA_ARGS__)
#define err(fmt, ...) _print_color(BRIGHT, RED, fmt, ##__VA_ARGS__)

#if 01
int main(void)
{
int i = 0;
for (i =0 ; i < 7; i++)
{
print_color(1, i, "color info test hello %s %d\n", "world", 250);
}
//warn("warn: hello %s %d \n", "world", 250);
//err("err: hello %s %d\n", "world", 250);
return 0;
}
#endif

附上许多年前写的Makefile的部分信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
### nothing
OFFSET=\x1b[21G   # 21 col
COLOR1=\x1b[0;32m # green
COLOR2=\x1b[1;35m # 
COLOR3=\x1b[1;31m # red
RESET=\x1b[0m


CLEAN_BEGIN=@echo -e "$(OFFSET)$(COLOR2)Cleaning up ...$(RESET)"
CLEAN_END=@echo -e "$(OFFSET)$(COLOR2)[Done.]$(RESET)"


MAKE_BEGIN=@echo -ne "$(OFFSET)$(COLOR1)Compiling ...$(RESET)"
MAKE_DONE="$(OFFSET)$(COLOR1)[Job done!]$(RESET)";
MAKE_ERR="$(OFFSET)$(COLOR3)[Oops!Error occurred]$(RESET)";
### nothing

all:
$(MAKE_BEGIN)
@echo 
@if \
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules;\
then echo -e $(MAKE_DONE)\
else \
echo -e  $(MAKE_ERR)\
exit 1; \
fi
endif

李迟 2015.1.26 中午