I recently wrote a post-receive git hook for a server and I wanted to easily distinguish my hook's output from git information. This led me to look into colorizing bash output.
By using ANSI color escape codes, we can add color to output strings. The ANSI standard specifies certain color codes;
Color | Foreground Code | Background Code |
---|---|---|
Black | 30 | 40 |
Red | 31 | 41 |
Green | 32 | 42 |
Yellow | 33 | 43 |
Blue | 34 | 44 |
Magenta | 35 | 45 |
Cyan | 36 | 46 |
Light Gray | 37 | 47 |
Gray | 90 | 100 |
Light Red | 91 | 101 |
Light Green | 92 | 102 |
Light Yellow | 93 | 103 |
Light Blue | 94 | 104 |
Light Magenta | 95 | 105 |
Light Cyan | 96 | 106 |
White | 97 | 107 |
To change the color of the text, what we want is the foreground code. There are also a few other non-color special codes that are relevant to us:
Code | Description |
---|---|
0 | Reset/Normal |
1 | Bold text |
2 | Faint text |
3 | Italics |
4 | Underlined text |
The echo
command prints out text. We need to tell it that we're working with special ANSI codes, not just regular characters. This can be accomplished by adding a \e
at the beginning to form an escape sequence. The escape sequence for specifying color codes is \e[COLORm
(COLOR represents our color code in this case). By default, echo
does not support escape sequences. We need to add the -e
option to enable their interpretation.
To print red text, therefore, we could have
echo -e "\e[32mRed text\e[0m"
The \e[0m
means we use the special code 0 to reset text color back to normal. Without this, all other text you print out after this would be red.
This works, but it would be more readable if we store the color codes in variables and use those instead.
RED="\e[31m"
ENDCOLOR="\e[0m"
echo -e "${RED}Red text${ENDCOLOR}"
Putting all these together, we could have a script like this
#! /usr/bin/env bash
RED="\e[31m"
GREEN="\e[32m"
ENDCOLOR="\e[0m"
echo -e "${RED}This is some red text, ${ENDCOLOR}"
echo -e "${GREEN}And this is some green text${ENDCOLOR}"
We can combine escape codes to get more fancy output.
#! /usr/bin/env bash
RED="31"
GREEN="32"
BOLDGREEN="\e[1;${GREEN}m"
ITALICRED="\e[3;${RED}m"
ENDCOLOR="\e[0m"
echo -e "${BOLDGREEN}Behold! Bold, green text.${ENDCOLOR}"
echo -e "${ITALICRED}Italian italics${ENDCOLOR}"
You can use these in any number of ways to make your scripts less monotonous. The combinations are up to you. Happy scripting!
Top comments (15)
Using escape codes directly is cool, but I'm a fan of using
tput
like this:There are a lot of handy things tput can do, and though the capabilities vary with your terminal, and though it's not completely portable either, you get all the colours your terminal can show.
I haven't heard about
tput
before. I'll definitely check it out.EDIT: Just took a look. It's great. Thanks for the tip 🚀.
Thanks for the great article. However in my environment, if I run the example, it will print the escape code literally. e.g.
For me the solution is to use
printf
, e.g.Try
$ echo -e "\033[32mRed text\e[0m"
. i.e.\e[32mRed text\033[0m
\033
instead\e
.Try using
-ne
rather than-e
.This helped me as well in macOS. Thank you!
I have RED already in use, so had to do this:
If you want to see the colors you can use this script: gist.github.com/dtmilano/4055d6df5... which uses
tput
.Thank you for the super helpful post.
I think the first example should be:
echo -e "\e[31mRed text\e[0m"
32
represents green.Great article. Something that should be simple but is actually super hard to understand thank you
Glad to help.
Great post!
Just add '5' as a blinking special, non-colour code ;)
Thanks for noticing! Fixed it.