Listing Terminal Colors
If you’ve ever worked with colors in a modern terminal emulator you may occasionally find yourself looking for just the right index to use in its standard 256-color palette. The other day I was in the same situation, so I wrote a little Bash script to print a pretty preview of all the colors. Here’s some sample output from Terminal.app (using the “Novel” profile):
Not bad! Now you could just download the script and call it a day, but what’s the fun in that? π If you’re game, let’s take a few minutes to go through the code together and figure out how it worksβ¦
First, we write a function to print each color index:
7padding=" "
8
9print_index () {
10 index=$1
11 printf "%s%s" "${padding:${#index}}" " $index "
12}
On line 7, we create a new string (padding
) of three whitespace characters. On line 10, we set the variable index
equal to the first parameter ($1
). Finally, on line 11, we print the index padded to a width of five characters. The result is right-justified, with a single space to the right of each index.
The syntax for the padding is a bit obtuse, so let’s break it down:
${variable}
is a more explicit way of writing$variable
, and simply returns the value of the given variable.${#variable}
returns the length of the given variable. Because Bash variables are just character strings, this returns the number of digits in the index.${variable:offset}
returns the value (substring) of the given variable starting from the specified offset.
So ${padding:${#index}}
returns a string with the number of whitespace characters in padding
less the number of digits in index
. More specifically, this expression returns two whitespace characters if index
has one digit; one whitespace character if index
has two digits; and an empty string if index
has three digits.
(For more details on this syntax, see the section on parameter substitution in the Advanced Bash-Scripting Guide.)
Next, we write a function to print each color:
14lut="\e[48;5;"
15reset="\e[0;39;49m"
16
17print_color () {
18 index=$1
19 printf "${lut}${index}m ${padding} ${reset}"
20}
On line 14, \e[48;5;
is the start of an ANSI escape sequence, where
\e[
is equivalent to theESC
ASCII control code (decimal value 27);48
is the Select Graphic Rendition (SGR) parameter to set the background color; and5
indicates that we are using a 256-color lookup table.
Similarly, on line 15, \e[0;39;49m
is an SGR control sequence that resets all display attributes (0
) before setting the default foreground (39
) and background (49
) colors.
(Note that the numbers in an SGR sequence are separated by semicolons and that a valid sequence must end in the ASCII character m
.)
On line 19, we bring this all together to display a color patch. Building on the explanation above, we can describe what the expression ${lut}${index}m ${padding} ${reset}
does as follows:
${lut}${index}m
expands to\e[48;5;${index}m
, selecting the color at the given index from a 256-color lookup table.β£${padding}β£
expands to five whitespace characters (the width of the color patch).${reset}
expands to\e[0;39;49m
, resetting all display attributes along with the foreground and background colors.
Now that we have our plumbing in place, let’s print the eight standard colors (indices 0β7) on a single line:
26bold="\e[1m"
27
28printf "\n${bold}Standard colors${reset}\n\n"
29for (( n=0; n<8; n+=1 )) ; do
30 print_index $n
31 print_color $n
32done
(Note that we’ve introduced a new SGR control sequence, \e[1m
, to make the heading text bold.)
We can print the eight “bright” colors (indices 8β15) the same way:
38printf "\n\n${bold}Bright colors${reset}\n\n"
39for (( n=8; n<16; n+=1 )) ; do
40 print_index $n
41 print_color $n
42done
Next, let’s print the 216 colors (indices 16β231) in the middle of the lookup table:
46printf "\n\n${bold}Colors #16-231${reset}\n"
47for (( n=16; n<232; n+=6 )) ; do
48 (( (n-16) % 36 )) || echo ""
49
50 for i in {0..5}; do
51 print_index $(( n+i ))
52 print_color $(( n+i ))
53 done
54
55 echo ""
56done
216 colors won’t really fit on a single line, so we’ll take the fact that they are arranged in a 6x6x6 “cube” into consideration and print them in 6x6 blocks, instead. We iterate through the indices six at a time (line 47), adding an extra space before each 6x6 block (line 48) and printing each index followed by a patch of its corresponding color (lines 50β53).
Finally, let’s print the 24 grayscale colors (indices 232β255):
60printf "\n${bold}Grayscale colors${reset}\n\n"
61for (( n=232; n<255; n+=6 )) ; do
62 for i in {0..5}; do
63 print_index $(( n+i ))
64 print_color $(( n+i ))
65 done
66
67 echo ""
68done
Once again, 24 colors won’t really fit on a single line, so we iterate through the indices six at a time (line 61), printing each index followed by a patch of its corresponding color (lines 62β65).
And that’s it! I hope you found this post to be helpful and/or edifying. Once again, you can download a copy of the script to use and modify as you see fit. Have a question or comment? Feel free to get in touch on Twitter or by email.
Happy coding! π