So You Like Color--The Mysterious ^[[ Characters
Have you ever redirected the output of a curses program with colors
and wondered what those mysterious ^[[ symbols are? Have
you ever tried to produce colors with a printf command without using
curses? If the answer to either of these questions is yes, read on.
This article attempts to explain the mysterious characters that one
finds in the output of a curses program that produces colors. Later,
we extend this concept to produce colors with a mere printf command.
Terminal Codes
In the old days of teletype terminals, terminals were located far away from
computers and were connected to them through serial cables. The
terminals could be configured by sending a series of bytes to each one.
All of the capabilities of terminals could be accessed through these
series of bytes, which usually are called escape sequences because they
start with an escape (0x1B) character. Even today, with vt100 emulation,
we can send escape sequences to the emulator that have the same
effect on the terminal window. Hence, in order to print color, we merely
echo a control code.
To start, type this on your console:
echo "^[[0;31;40mIn Color"
The first character is an escape character, which looks like two
characters, ^ and [. To be able to print this, you have to press CTRL+V
and then the ESC key. All the other characters are normal printable
characters, so you see the string In Color in red. The type
stays that color until you revery back by typing this:
echo "^[[0;37;40m"
As you can see, it is easy to set and reset colors in a console or xterm.
A myriad of escape sequences are available with which you can do a lot
of things, including moving the cursor and resetting the terminal.
The Color Code: <ESC>[{attr};{fg};{bg}m
Now, I explain the escape sequence used to produce colors. The sequence to be
printed or echoed to the terminal is
<ESC>[{attr};{fg};{bg}m
The first character is ESC, which has to be entered by pressing CTRL+V
and then ESC on the Linux console or in xterm, konsole, kvt and so on.
Incidentally, CTRL+V ESC also is the combination used to embed an
Esc character in a document in Vim. Then, {attr}, {fg} and {bg} have to be
replaced with the correct value to achieve the corresponding effect. attr is
the attribute, such as blinking or underlined text, while fg and bg are foreground
and background colors, respectively. You don't have to put braces around
the number; simply writing the number is sufficient.
{attr} needs to be one of the following:
- 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} needs to be one of the following:
- 30 Black
- 31 Red
- 32 Green
- 33 Yellow
- 34 Blue
- 35 Magenta
- 36 Cyan
- 37 White
{bg} needs to be one of the following:
- 40 Black
- 41 Red
- 42 Green
- 43 Yellow
- 44 Blue
- 45 Magenta
- 46 Cyan
- 47 White
So, to get a blinking line with a blue foreground and a green background, the
combination should be:
echo "^[[5;34;42mIn color"
which actually is very ugly. So, revert back with
echo "^[0;37;40m"
With printf()
What if you want to use this code color and attribute functionality in a
C program? Well, that's simple. Before you printf something, print the escape
sequence to produce it in the desired color. I have written a small
routine, textcolor(), that does this automatically for you. You can use it in
your C programs, along with the #define constants.
|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);
}
The textcolor() program is modeled against the Turbo C API
function. You call the function to set the color and then print it with
sprintf(), a function used in Turbo C to produce console
output in color.
A Demo of Colors
The following program asks the user to play with attributes and colors
and then shows a text string in those colors and with those attributes.
I usually use it to find the best combination of colors for my GUIs.
#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);
}
The Catch
So, what's the catch? If producing colors and attributes for text
is so easy, why do people waste their time writing huge programs in
curses, which in turn queries terminfo in a complex way? As we know,
many terminals are out there that have few capabilities. Others don't
recognize these escape codes or need different codes entered to achieve
the same effect. So, if you want a portable program that can run on
various terminals with the same or reduced functionalities, you should use
curses. Curses uses terminfo to find the correct codes to accomplish
these types of tasks across various terminals. Terminfo is a large database
that contains information about the various functionalities of different
terminals.
But, if you simply want to write a program that produces color on a
Linux console or in an xterm window, you can use the escape sequences
above to do it easily. The Linux console mostly emulates vt100, so it
recognizes these escape sequences.
With tput
However, there is a way to query the terminfo database for the
information you need and do the work yourself. tput
is the command that queries the database and executes the functionality
you specify. The two capabilities setf and setb are useful to set
foreground and background colors. For example, use the following to
set the foreground color to red and the background color to green:
tput setf 4 # tput setf {fg color number}
tput setb 2 # tput setb {bg color number}
These commands can be used in shell scripts wherever you want. See
the tput man page for additional capabilities of tput. The terminfo man
pages contain a lot of information regarding terminal capabilities, how to get and
set their values and more. There are two terminfo man pages: man 5
terminfo describes the terminfo database, and man 3ncurses
terminfo describes the C functions that use the database.
Here are the numbers to be passed as arguments to tput setf and
tput setb and their corresponding colors:
- 0 Black
- 1 Red
- 2 Green
- 3 Yellow
- 4 Blue
- 5 Magenta
- 6 Cyan
- 7 White
Resources
The
Text-Terminal-HOWTO
Man pages for
tput and
terminfo.
Copyright (c) 2001, Pradeep Padala. Originally published in Linux Gazette
issue 65. Copyright (c) 2001, Specialized Systems Consultants, Inc.
Pradeep Padala has a BE (equivalent to BS) in Computer Science and
Engineering. His interests include solving puzzles and playing board
games.










This week 5 lucky Members will receive a copy of The Official Ubuntu Server Book by Benjamin Mako Hill and Linux Journal's very own Kyle Rankin. No entry necessary. Check back here early next week to find out who the lucky Online Members are.




Comments
Bypass the need for CTRL-V ESC
If you want to omit the CTRL-V ESC key sequence you can use \033 instead.
So the lines would read echo "\033[0;31;40m In Color"
and echo "\033[0;37;40m"
This makes it easier to type and to have in scripts.
Excellent post
A fantastic post, I'm just about to do some scripts involving interpreting these colour codes from the logs from the screen utility, this page was invaluable.
Keep up the good work :-)
Cool Tutorial, but...
Cool tutorial, but, I noticed that in the two coding examples you #define BLINK as 4, when it's actually supposed to be '5'
It's just a small type-o, but I thought I'd let you know just incase someone (such as myself) tries to learn from one of the examples without first looking to the list that correctly defines BLINK as 5.
Inspired me to write a library
It's been a slow day before exams started, so I went and wrote a C header I've named SimpleColors after reading this article: CVS (tarball). Great information!
This link is broken!
This link is broken!
awesome
OMG, this is awesome. I've been wondering for about three years how to do colors in c(besides using ncurses). I just happened to be bored and decided to checkout lj's website since I have a subscription and really like the mag.
I think the editors are retarded for not putting this stuff in the magazine. I mean, I have to look at a computer monitor 12 hours a day and I'd really rather go home and read this stuff from the print mag.
But anyway, awsome article Pradeep. Thanks!
bugs in code
In your while loop, the second and third
ifstatements are incorrect. It looks like you copied/pasted the first statement and did not change the conditions -- you are comparingattrwhen it should befgand thenbg.RE: bugs in code
Sorry, forgot to mention that is for the "Demo of Colors" program.
Will Linux make computers soo
Will Linux make computers soon?
http://blog.detectivemarketing.com/2005/10/will-linux-make-computers-soon.html
LINUX is no brand
and never will be. So Linux as a organization could not exist. And you cannot build real material things over the web, cause your hands doesnt fit into the cables :)
Re:
In USSR was not any commercical company. But this counrty was better than USA.
Communism rulezzz!
Such a thing could be
Such a thing could be written by the person who never lived in both countries nor US nor USSR. It seems the author of the previous comment is a teen who grown up in Ukraine as an independent country and considers that USSR was a communist state... Funny :)
look it up
Actually the Ukraine beeing a part of the USSR is not that long ago! They became independant 1991.
cool article. i finally under
cool article. i finally understood colors... although a msg about that it is not possible to paste the escape sequence into your terminal would be good.
But what about outputting to a file?
Hi, I use escape sequences in my program but then if I redirect the output to a file, I start seeing all these escape characters in there. Is there a way that I can disable this functionality when outputting to a file?
istty
http://www.thinkage.ca/english/gcos/expl/c/lib/istty.html
Post new comment