Disclaimer don't get the wrong idea about what you've found here

What appears below are my personal notes I wish were part of my long-term memory but don't always seem to fit. I strive for accuracy and clarity and appreciate feedback. If applying any of this information anywhere, confirm for youself the correctness of your work as what you see below might very well be, albeit unintentionally, incorrect or misleading. These notes are here as an easy reference for myself.

Information worthy of a more formal presentation will appear elsewhere than this "Scratch" area. - ksb


KSB's bash color prompt notes

I like having a color prompt. Helps in finding where a command started or stopped when scrolling back in the terminal. I also like having lots of info in that prompt, like: user, host, current dir, time (with secs), the return code of the last command and an extra hint if I might be root.

Getting all that right has been surprisingly difficult. I've finally figured out why and here's my solution:

Table of Contents References

Basics

The default bash prompt is:

PS1='\u@\h\$ '
ksb@fuzz$ 
As you can see, this gives a prompt consisting of: user name, '@' sign, hostname, '$' symbol (or '#' if you're root) and a space.

You can get colors into your prompt by using escape codes. One code to start the color another to stop it, each surrounded by another kind of escape code to prevent those first ones from confusing bash's idea of how big the prompt is (fun, huh?).

This size of the prompt notion is important when hitting up-arrow and try editing the previous command, or using ctrl-r to search back in your history, or using cut-n-paste, etc. Otherwise your terminal can become quite a mess.

For example to make the above prompt green use:

PS1='\[\e[0;32m\]\u@\h\$\[\e[0m\] '
ksb@fuzz$ 
See the references above for a complete explanation of all this, but briefly breaking this value down into each of its 8 parts:
\[ stop counting towards length of prompt for now
\e[0;32m starting coloring non-bold green
\] start counting towards length of prompt again
\u@\h\$ the prompt: 'user@host$'
\[ again stop counting towards length of prompt for now
\e[0m reset to no colors
\] again start counting towards length of prompt again
a final space (visually this help separate the prompt for your commands)

Bash Version 3 Prompt Bugs

My preferred non-color bash prompt is:

PS1='\u@\h[\W] \t ($?)\$ '
ksb@fuzz[~] 15:55:58 (0)$ 

This starts off with the default prompt but then adds: current dir (basename), time (with secs) and the return code of last command. Note that the use of single quotes to set that var is important since I want the $? evaluated each time the prompt is presented, not just once when PS1 var is set (which is what would happen if double-quotes were used).

Colorizing this revealed 2 bugs in bash version 3, which appear to have been fixed in bash 4:

  1. The '\t' appears to confuse the calculation of length of the prompt despite using all the above quoting. Using '\A' works but then you loose seconds being displayed.

  2. Parentheses also confuse the calculation of length of the prompt. My work-around here is to just not used them.

Tricks

Following the idea from the link above, I defined several vars in my ~/.bashrc

blk='\e[0;30m' # Black - Regular
red='\e[0;31m' # Red
grn='\e[0;32m' # Green
ylw='\e[0;33m' # Yellow
blu='\e[0;34m' # Blue
pur='\e[0;35m' # Purple
cyn='\e[0;36m' # Cyan
wht='\e[0;37m' # White
bblk='\e[1;30m' # Black - Bold
bred='\e[1;31m' # Red
bgrn='\e[1;32m' # Green
bylw='\e[1;33m' # Yellow
bblu='\e[1;34m' # Blue
bpur='\e[1;35m' # Purple
bcyn='\e[1;36m' # Cyan
bwht='\e[1;37m' # White
ublk='\e[4;30m' # Black - Underline
ured='\e[4;31m' # Red
ugrn='\e[4;32m' # Green
uylw='\e[4;33m' # Yellow
ublu='\e[4;34m' # Blue
upur='\e[4;35m' # Purple
ucyn='\e[4;36m' # Cyan
uwht='\e[4;37m' # White
bkblk='\e[40m'   # Black - Background
bkred='\e[41m'   # Red
bdgrn='\e[42m'   # Green
bkylw='\e[43m'   # Yellow
bkblu='\e[44m'   # Blue
bkpur='\e[45m'   # Purple
bkcyn='\e[46m'   # Cyan
bkwht='\e[47m'   # White
rst='\e[0m'    # Text Reset
and then define my prompt like this:
PS1="\[$ylw\]\u\[$rst\]@\[$ylw\]\h\[$rst\][\[$cyn\]\W\[$rst\]] \[$grn\]\t\[$rst\] (\[$red\]"'$?'"\[$rst\])\\$ "

Something to point out here is that I need to use double-quotes here for all those 'simplifying' vars to be evaluated. Except of course where I don't want it for the '$?' which I don't want evaluated until the prompt is displayed after each command. Fortunately (and I had to double check this) bash concatenates contiguous strings, so I break it out into 3 separate strings. This leaves the prompt with the value:

ksb@fuzz[~] 18:05:04 (0)$ echo $PS1
\[\e[0;33m\]\u\[\e[0m\]@\[\e[0;33m\]\h\[\e[0m\][\[\e[0;36m\]\W\[\e[0m\]] \[\e[0;32m\]\t\[\e[0m\] (\[\e[0;31m\]$?\[\e[0m\])\$
Another thing you might notice is that final \\$. This needs those 2 backslashes so the resulting PS1 var will end up with the desired \$. I think that makes the above an example of 4 different kinds of quotes!

Finally, I'd need to write some conditionals around all this to check both the version of bash to avoid \t & parentheses.


Keith S. Beattie is responsible for this document, located at http://dst.lbl.gov/~ksb/Scratch/bash_color_prompt.html, which is subject to LBNL's Privacy & Security Notice, Copyright Status and Disclaimers.

Last Modified: Monday, 25-Feb-2013 16:57:57 PST