DEV Community

Luca
Luca

Posted on • Edited on

Customize shell prompt

Change the appearance of the terminal shell prompt: customize colors, text formatting, and dynamically display other type of information (including git status).

We're going to use bash on Ubuntu but most concepts can also be applied in other unix-based systems (e.g. MacOS and Windows Subsystem for Linux).

Prompts variables

Bash has four type of prompts controlled by those variables:

  • PS1 primary prompt.
  • PS2 displayed when you've to type more commands (multi-line commands).
  • PS3 displayed when the select command is waiting for input.
  • PS4 displayed when debugging Bash scripts.

If you echo $PS1 you'll see a bunch of characters sequences:

\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$
Enter fullscreen mode Exit fullscreen mode

When you enter an interactive shell session, the shell read PS1 and output something like this:

username@hostname:directory$
Enter fullscreen mode Exit fullscreen mode

The dollar $ symbol at the end signifies that you're a normal user, for root user it's replaced with the hash # symbol.

If you echo $PS2 it'll display only the greater-than sign > symbol.

You can see both PS1 and PS2 in the screenshot below:

The PS3 and PS4 prompts are not very common. In this guide we'll focus on the primary prompt.

Change the prompt

To control the output of your primary prompt, edit the PS1 variable:

PS1='my_prompt: '
Enter fullscreen mode Exit fullscreen mode

Because PS1 was replaced directly in Bash, changes will disappear on shell exit. Later in this guide we'll learn how to make this changes permanent.

Embedding commands

You can run commands inside PS1 variable:

PS1='$(exit_status=$? ; if test $exit_status -ne 0 ; then echo "(err)" ; fi)my_prompt: '
Enter fullscreen mode Exit fullscreen mode

If exit code is not equal to 0 it'll display (err).

Backslash-escaped characters

There are some backslash-escaped special characters you can use to dynamically display useful information in the prompt.

For example:

PS1='\t \u \h \w \$ '
Enter fullscreen mode Exit fullscreen mode
  • \t display time.
  • \u display user name.
  • \h display hostname.
  • \w display current working directory.
  • \$ display dollar $ symbol if you're normal user; display hash # symbol if you're root user.

Here is a complete list of backslash-escaped characters.

ANSI escape sequences

Bash allows the user to call a series of ANSI escape sequences to change colors, text formatting, cursor location and other options of the terminal window. Those sequences are a set of non-printable control characters which the shell interprets as commands.

An ANSI escape sequence always start with an escape character and a left-bracket character, followed by one or more control characters:

ESC[COMMAND
Enter fullscreen mode Exit fullscreen mode
  • The escape character ESC can be written as \033 or \e or \x1b.
  • COMMAND is the control character.

See the list of ANSI sequences for all available commands (some terminals may have partial support for ANSI sequences).

Colors and text formatting

To colorize the output of your text terminal use the following ANSI sequence:

ESC[CODEm
Enter fullscreen mode Exit fullscreen mode

Where CODE is a series of one or more semicolon-separated color codes.

For example:

echo -e "\033[44mHello World\033[0m"
Enter fullscreen mode Exit fullscreen mode
  • -e enable echo to parse escape sequences.
  • \033[ mark the start of an ANSI sequence.
  • 44 is the code for background color blue.
  • m mark the end of color codes.
  • 0 removes all text attributes (formatting and colors). It's important to reset attributes, otherwise the styles will be applied to all texts after Hello World (including the prompt and the text we type).

You can also modify a color by setting an "attribute" before its base value, separated by a ; semi-colon.

So if you want a green background (46) with underline text (4), the sequence is:

echo -e "\033[4;46mHello World\033[0m"
Enter fullscreen mode Exit fullscreen mode

You can combine multiple sequences together:

echo -e "\033[41m\033[4m\033[1;33mHello World\033[0m"
Enter fullscreen mode Exit fullscreen mode

Here you can find a list of all color codes.

Save prompt changes permanently

To make the changes permanent you can modify the default PS1 variable or add a new one at the end of ~/.bashrc file:

PS1='$(exit_status=$? ; if test $exit_status -ne 0 ; then echo -e "(\[\033[31m\]err\[\033[0m\])${debian_chroot:+($debian_chroot)}" ; else echo ${debian_chroot:+($debian_chroot)} ; fi)\[\033[1;33m\]\u@\h\[\033[0m\]:\[\033[1;36m\]\w\[\033[0m\]\$ '
Enter fullscreen mode Exit fullscreen mode

Non-printing characters must be surrounded with escaped square brackets \[ (start of non-printing characters) and \] (end of non-printing characters). For example \[\033[1;33m\]. Otherwise Bash think they're printing characters and use them to calculate its size (cause the text to wraps badly before it gets to the edge of the terminal).

This line ${debian_chroot:+($debian_chroot)} display to your prompt an indication of which chroot you're in.

You can use source ~/.bashrc to refresh the changes instead of exit and re-enter the shell.

Display git repository status

Git provide a script that allows to see repository status in your prompt.

Download git-prompt.sh:

curl -o ~/.git-prompt.sh https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh
Enter fullscreen mode Exit fullscreen mode

The script comes with a function __git_ps1 that can be used in two ways:

  • You can call it inside PS1 (this way you can't see colored hints).
  • Or you can call it inside PROMPT_COMMAND (with this method you can enable colored hints).

By default __git_ps1 will show only the branch you're in, you can also enable git status through a series of variables whose names start with GIT_PS1_SHOW*.

If you don't want colored hints you can simply use $(__git_ps1 "(%s)") inside PS1 and sets GIT_PS1_SHOW* variables as you prefer.

To show colored hints you cannot edit PS1 directly. Instead, you have to call __git_ps1 function inside PROMPT_COMMAND variable. If PROMPT_COMMAND is set, the value is interpreted as a command to execute before the printing of primary prompt. In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true.

Add the following code at the end of ~/.bashrc file:

source ~/.git-prompt.sh

GIT_PS1_SHOWDIRTYSTATE="true"
GIT_PS1_SHOWSTASHSTATE="true"
GIT_PS1_SHOWUNTRACKEDFILES="true"
GIT_PS1_SHOWUPSTREAM="auto"
# Colored hints work only if __git_ps1 is called inside PROMPT_COMMAND
GIT_PS1_SHOWCOLORHINTS=true

PROMPT_COMMAND='__git_ps1 "$(exit_status=$? ; if test $exit_status -ne 0 ; then echo -e "(\[\033[31m\]err\[\033[0m\])${debian_chroot:+($debian_chroot)}" ; else echo ${debian_chroot:+($debian_chroot)} ; fi)\[\033[1;33m\]\u@\h\[\033[0m\]:\[\033[1;36m\]\w\[\033[0m\]" "\$ " "(%s)"'
Enter fullscreen mode Exit fullscreen mode
  • source ~/.git-prompt.sh will load git-prompt.sh script.
  • GIT_PS1_SHOW* variables are used to add additional features.
  • If __git_ps1 is used inside PROMPT_COMMAND it must be called with at least two arguments, the first is prepended and the second appended to the state string when assigned to PS1. There is an optional argument used as printf format string to further customize the output (%s is the output of __git_ps1 which in this case is wrapped in parenthesis).

For more info read comments inside ~/.git-prompt.sh file.

External resources

Top comments (0)