Customize the bash prompt

Display of additional information in the bash prompt

The bash prompt is not statically fixed but can be adapted by the system administrator for all users and by the individual user for himself. This article shows how to get additional information into the bash prompt.

Definition of the command prompt

The content and appearance of the bash prompt are defined using the PS1 environment variable. You can find out how the current input prompt is defined by outputting the content of the variable PS1:

uwe@Caboto:~$ echo $PS1
${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$
uwe@Caboto:~$

What initially looks like incomprehensible gibberish can be broken down relatively easily:

${debian_chroot:+($debian_chroot)} – This sequence provides additional content if the shell is currently in a chroot environment. This is usually not the case and then nothing is issued.

\[\033[01;32m\] – With \[…\], a sequence of non-printable characters is generally embedded, in this case \033[01;32m, which changes the color of the subsequent (printable) characters to green ("light green"). These characters are

\u@\h\u und \h are two of several possible macros that can be used in the command prompt, \u contains the current user name and \h the current computer name. The @ character is placed between the two.

The previously changed attributes are then reset with \[\033[00m\] so that the text appears in white again. Then it follows a colon : and then again with \[\033[01;34m\] the color changes to blue ("light blue"), in which the current working directory is output with the macro \w. The attributes are reset again with \[\033[00m\].

Finally, with the macro \$ a $ character is actually displayed if the current user is not the system administrator root, whereas with this macro a # character is displayed for root.

The goal is now to adapt the command prompt so that when changing to a directory that is subject to versioning with Git, the current branch and the current tag (if any) are displayed in the command prompt.

View a git repository in bash

The directory /home/uwe/ProjectDir/MyProject/ is the base directory of a project that is managed with Git. In bash it might look something like this:

View of a git project in bash

By using the command git branch or git rev-parse --abbrev-ref HEAD you can find out which branch you are on in a Git repository:

$ git rev-parse --abrev-ref HEAD
master
$

If you are not in a directory of a Git repository, an error message appears:

$ git rev-parse --abrev-ref HEAD
fatal: not a git repository (or any of the parent directories): .git
$

To find out if there is a tag, you can use the git describe command. This gives the same error message as above if you are not in a Git repository and a different one if there is no tag in the repository:

$ git describe
fatal: No names found, cannot describe anything.
$

In case there is a tag, it will be displayed:

$ git describe
v3.2.12
$

In order to make this information available with the help of a single command, we first have to define a bash function that outputs exactly this content.

Define a function current_git_branch

The appropriate place for function definitions is the user-specific bash configuration file, .bashrc, which is called and executed when a bash is started. It is always available in the user's home directory and already contains some settings.

Another, even better option would be to store function definitions in an additional file, e.g. .bash_functions and then source this file in the .bashrc. The sourcing should take place relatively at the beginning of the .bashrc, since you may want to access the defined functions at a later point within the .bashrc. It should look like this:

if [ -f ~/.bash_functions ]; then
    . ~/.bash_functions
fi

This means, if the .bash_functions file exists in the user's home directory (~), it is sourced and the function definitions herein are executed, otherwise nothing happens.

The definition of the function current_git_branch - which can also be named completely different - looks like this:

function current_git_branch {
  local version=$(git describe 2>/dev/null);
  local branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null);
  if [[ -n $branch ]];then
    echo " [$branch/$version]";
  fi
}

The output of the git describe command is stored in the locally scoped variable version by means of the $(...) construct. It is important that any error is sent to nothing with 2>/dev/null, so that the variable is empty in that case.

In the same way, the output from git rev-parse --abbrev-ref HEAD is stored in the variable branch.

Afterwards, If the branch variable is not empty, the contents of the variables branch and version are displayed in square brackets, tied together by a / character and preceded by a space.

The function can be tested within a new bash or by sourcing the .bashrc (or .bash_functions). Just run the command current_git_branch. If the current directory is not under version control nothing will appear, otherwise e.g. [master/] or [master/1.2.3] will be displayed, depending on which branch you are currently in and whether there is a tag or not.

Adding the function to the command prompt

The output of the current_git_branch command is now added to the command prompt at a suitable location using $(current_git_branch), ideally after the current directory macro (\w) and before the \$ macro. To accomplish this, the definition of the PS1 variable in the .bashrc must be changed.

The definition of the variable PS1 usually ends with:

PS1='...\w\[\033[00m\]\$ '

This will be changed to:

PS1='...\w$(current_git_branch)\[\033[00m\]\$ '

As soon as you have started a new bash or re-sourced the .bashrc, the new prompt takes effect:

View of a git project in bash

Further reading

Bash Prompt HOWTO: Chapter 6. ANSI Escape Sequences: Colours and Cursor Movement

Top