Bash Prompts

The default bash prompt is useful, but can be customised considerable. In this article I show you what you can use in it and some examples of some advanced techniques for improving your prompt to show more useful information.

Types of prompts

Bash has four different prompts controlled by environment variables called PS1PS2PS3 andPS4. Each prompt is used in particular places. The most common prompt is PS1, which controls the main prompt you see at the command line. PS2 is the continuation prompt, used when you don’t close a string or use the line continuation marker (\ at the end of a line). The other two are rather rarer. PS3 is used when you use the select builtin command. PS4 is used to show traced calls when you use set -x. The default is '+ '.

 
Prompt Description Default
PS1 Default interactive prompt. ‘\s-\v\$ ’
PS2 Continuation interactive prompt ‘> ’
PS3 Prompt used by the select builtin.
PS4 Used by set -x to prefix tracing output. '+ '

Prompt expansion items

Bash has a large number of special character sequences you can use in prompts. You can also include any ordinary bash expansions, including variables and command expansions.

 
Prompt Description Example Result
\a An ASCII bell character (07) \a$ $ (and beep)
\d The date in “Weekday Month Date” format \d$ Wed Mar 08$
\e An ASCII escape character (033)
\h The hostname up to the first `.’ \h$ beebo$
\H The hostname \H$ beebo.example.com$
\j The number of jobs currently managed by the shell \j$ 0$
\l The basename of the shell’s terminal device name \l$ 1$
\n Newline \d\n\h$ Wed Mar 08 <newline>beebo$
\r Carriage return \d\r\h$ beebo$r 08
\s The name of the shell, the basename of $0 (the portion following the final slash) \s$ bash$
\t The current time in 24-hour HH:MM:SS format \t$ 07:24:57$
\T The current time in 12-hour HH:MM:SS format \T$ 07:24:57$
\@ The current time in 12-hour am/pm format \@$ 07:25 AM$
\u The username of the current user \u$ david$
\v The version of bash (e.g., 2.00) \v$ 3.1$
\V The release of bash, version + patchlevel (e.g., 2.00.0) \V$ 3.1.5$
\w The current working directory \w$ ~/articles/bash-prompts$
\W The basename of the current working directory \W$ bash-prompts$
\! The history number of this command \!$ 537$
\# The command number of this command \#$ 40$
\$ If the effective UID is 0, a #, otherwise a $ \$ $ or # as root
\nnn The character corresponding to the octal number nnn \141$ a$
\\ A backslash \\$ \$
\[ Begin a sequence of non-printing characters, which could be used to embed a terminal control sequence into the prompt
\] End a sequence of non-printing characters

The bash default is \s-\v\$ , which results in bash-3.1$, which isn’t very exciting. The default in Debian (and most other linux distributions) is ‘\u@\h:\w\$ ‘, which results indavid@beebo:~/articles/bash-prompts$, which is much more useful. My preference is to show my username rather than the current directory because I tend to use several different users and I want to know who I am, so I use \h \u% .

Using colour

I tend to find that if I’m using a white prompt I can’t easily tell where the start of a command was when scrolling back. To fix this I made my prompt stand out by making it colourful. You can do this using the terminal control sequences for your terminal. In my case I use VT100 escape codes, which have worked on every terminal I’ve tried, but you may need to test first. I put the following in my ~/.bashrc:

STARTCOLOUR='\e[31m';
ENDCOLOR="\e[0m"
PS1="$STARTCOLOUR\h \u% $ENDCOLOR"

Here we can see that <escape>[31m is the VT100 code for red and <escape>[0m is the code for white. There is a little problem here in that the shell doesn’t know that these characters are not printed, so think that the prompt is 22 characters long (host is 5 and username is 5), when in fact only 13 get displayed. This results in bash wrapping lines at the wrong place. This is what the mysterious \[ and \] are for. They tell bash that the characters between them don’t actually display on the screen. So now we have:

STARTCOLOUR='\[\e[31m\]';
ENDCOLOR="\[\e[0m\]"
PS1="$STARTCOLOUR\h \u% $ENDCOLOR"

This is much better and doesn’t corrupt the display. Now wouldn’t it be nice if you could tell the difference between an ordinary user and root a little easier. To do this, I made root’s prompt cyan rather than red. This way I know a cyan prompt means I should be careful. This resulted in:

case $(id -u) in
    0)
        STARTCOLOUR='\[\e[36m\]';
        ;;
    *)
        STARTCOLOUR='\[\e[31m\]';
        ;;
esac
ENDCOLOR="\[\e[0m\]"
PS1="$STARTCOLOUR\h \u% $ENDCOLOR";

Change xterm titles

One interesting feature of my bash prompt is that it includes the host and the current directory in the xterm title bar, which is very useful for switching windows or tabs on gnome-terminal or konsole. This is done by using another escape sequence that xterms understand. You only want xterms to do this, so we check to see if we are on an xterm. This results in:

case $(id -u) in
    0)
        STARTCOLOUR='\[\e[36m\]';
        ;;
    *)
        STARTCOLOUR='\[\e[31m\]';
        ;;
esac
ENDCOLOR="\[\e[0m\]"
case $TERM in
    xterm*)
        TITLEBAR='\[\e]0;\h \w\007\]';
        ;;
    *)
        TITLEBAR="";
        ;;
esac

PS1="$TITLEBAR$STARTCOLOUR\h \u% $ENDCOLOR"

Any article wouldn’t be complete without a gratuitous screenshot, so here you go:

Display of a bash prompt