Linux: Colorful Bash Prompt
Date: 21 Feb, 2021
Reading Time: 5 min
Lately I have been working with my server a lot, and noticed that its Bash prompt is rather boring and with no color at all:

So I decided to change this and bring some color to my server! Also, I wanted to use different colors for ordinary users and root, so it is easy to see if I am currently in the danger zone (i.e. root).
Everything in this blog post was done on Arch Linux, which runs on all my Linux boxes at the time of writing. It is however likely it will also work with other Linux distributions as well, but configuration files and such might be in different locations. The Bash version used was 5.1. |
Some Basics
Bash has a couple of locations where it takes its configuration from,
/etc/bash.bashrc
for system-wide settings and ~/.bashrc
for per-user settings in case of an interactive shell (the "normal" terminal).
Colors on the Terminal
Colors are set via ECMA-48 SGR sequences (SGR stands for Set Graphics Rendition), which is one of the ECMA-48 CSI sequences (CSI stands for Control Sequence Introducer)[3].
This is the basic anatomy of such an SGR sequence: \e[p1;p2;pNm
\e
is the Bash way of writing down the <ESC>
(1bhex) character, and combined with [
it makes up a CSI.
p1
, p2
and pN
are 0..n parameters, which are divided by the ;
character.
Finally, the trailing m
character makes the CSI sequence an SGR action, which is able to set a color,
but also other aspects like bold text or underlined text, depending on the terminal’s capabilities.
A modern terminal has basically three different kinds of text/foreground colors:
-
predefined named colors
-
black:
\e[30m
, bright black:\e[90m
-
red:
\e[31m
, bright red:\e[91m
-
green:
\e[32m
, bright green:\e[91m
-
brown:
\e[33m
, bright brown:\e[93m
-
blue:
\e[34m
, bright blue:\e[94m
-
magenta:
\e[35m
, bright magenta:\e[95m
-
cyan:
\e[36m
, bright cyan:\e[96m
-
white:
\e[37m
, bright white:\e[97m
-
-
265 colors
-
\e[38;5;Xm
|X=0..15
: equivalent to the named colors, first the3x
ones and then the9x
ones -
\e[38;5;Ym
|Y=16..231
: a 6x6x6 color-cube[4] -
\e[38;5;Zm
|Z=232..255
: a grayscale ramp going from black (232) to white (255)
-
-
24-bit colors
-
\e[38;2;R;G;Bm
|R,G,B=0..255
: directly defined RGB color (r=red, g=green, b=blue)
-
Last but not least there is also \e[0m
which simply resets all previously set SGR attributes.
The named colors can be redefined, e.g. by a terminal emulator, whereas the others are "hardcoded". This is important to consider when using terminal-emulators which support color-themes, especially when lots of people are using the respective computer (some might prefer dark themes and other light ones). These emulators typically use redefinition of the named colors to keep things readable depending on the background color, which is not possible for the other kinds of colors. |
To see the fairly theoretical stuff from above in action, I decided to create a Bash script which demonstrates the things explained above. The script simply prints the escape sequences in the text/foreground color produced by it, so it is easy to choose a color and just copy the escape sequence. This script can be downloaded here: https://github.com/luossfi/bash-helpers/blob/main/terminal-text-color-demo.
Executing this script yields the following output (much more actually, but this would not reasonably fit into an image):

The image also demonstrates the difference between the 16 named colors and the others, by setting different themes in the terminal emulator. The named colors change along with the theme, the others do not.
Putting Everything Together
I decided to stick with the named colors, so theming will work as expected and this is my coloring choice:
-
username: light red (
\e[91m
) for root, light green (\e[92m
) otherwise -
hostname: light cyan (
\e[96m
) -
current directory: light brown (
\e[93m
), which look more like yellow, actually
It is also important to put these escape sequences between \[
and \]
, which mark a sequence of non-printing characters[2].
This is important for calculating the resulting prompt’s length, correctly.
This is the resulting Bash configuration snippet:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# [...]
GREEN='\[\e[92m\]' (1)
RED='\[\e[91m\]' (1)
CYAN='\[\e[96m\]' (1)
YELLOW='\[\e[93m\]' (1)
RESET='\[\e[0m\]' (2)
if [ "$(whoami)" = 'root' ] (3)
then
PS1="${RESET}[${RED}\u${RESET}@${CYAN}\h ${YELLOW}\w${RESET}]\$ " (4)
else
PS1="${RESET}[${GREEN}\u${RESET}@${CYAN}\h ${YELLOW}\w${RESET}]\$ " (4)
fi
# [...]
1 | Define variables containing the escape sequences for green, red, turquoise and yellow, so the actual prompt definition is easier to understand. |
2 | Define the reset escape sequence, so colors can be set to the terminal’s default. |
3 | Handle user root differently as all other users. I decided to have a red username (\u ) for root and a green one for all others. |
4 | Use the variables defined above for defining the actual prompt.
The trailing whitespace is intentional, otherwise the cursor would be right next to the $ . |
Finally, this is the resulting Bash prompt:

When using the root
account, its username is printed in red, and if using a "normal" user account, its username is printed in green!