Understanding color codes in the terminal

Everyone loves colors in the terminal, but how do they work?

The way colors are set is by sending a control character called escape (not to be confused with an escape character.)

In ASCII esc is a specific character with the value 0x1b, often being written in caret notation as ^[.

In technical documents ^[ is often denoted as CSI, or Control Sequence Introducer.

In order to modify graphics, we send the SGR sequence (short for Select Graphic Rendition.)

The SGR sequence is structured like this;

CSI [ <parameters> m

The parameters that we'll be focusing on are as follows;

0      default rendition; cancels the effects of any previous SGR occurence
3[0-7] sets the foreground color
4[0-7] sets the background color
38     extended set foreground color
48     extended set background color

Originally the specification only supported 8 colors, though some implemented a "bright" mode by complementing bold mode (SGR 1) to the default colors.

Intensity 0 1 2 3 4 5 6 7
Normal Black Red Green Yellow Blue Magenta Cyan White
Bright Black Red Green Yellow Blue Magenta Cyan White

As color technology advanced, it was decided to add 256-color support to terminals. For this, they used the SGR 38 as it was reserved for future use.

The reserved extended set allowed two argument forms, and both forms are implemented in many terminal emulators today.

^[ [ 38;5;<N> m
^[ [ 38;2;<R>;<G>;<B> m

The former setting the color to N, where N is one of the predefined 256 colors. The latter takes a RGB values.

If we look at calmar.ws's 256 index, we can pick any color, like for example 154, and print it out using printf.

printf 'here is text with \033[38;5;154m color \033[0m and  without\n'

Or to print a table of all the 256 colors

jot 255 | while read
do
    printf '\033[48;5;%dm   \033[0m ' $REPLY
done
echo # flush

If you don't have jot installed, replace it with seq.