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\]\$
When you enter an interactive shell session, the shell read PS1
and output something like this:
username@hostname:directory$
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: '
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: '
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 \$ '
-
\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
- 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
Where CODE
is a series of one or more semicolon-separated color codes.
For example:
echo -e "\033[44mHello World\033[0m"
-
-e
enableecho
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"
You can combine multiple sequences together:
echo -e "\033[41m\033[4m\033[1;33mHello World\033[0m"
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\]\$ '
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
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)"'
-
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 insidePROMPT_COMMAND
it must be called with at least two arguments, the first is prepended and the second appended to the state string when assigned toPS1
. 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
- https://www.digitalocean.com/community/tutorials/how-to-customize-your-bash-prompt-on-a-linux-vps
- https://misc.flogisoft.com/bash/home
- https://wiki.archlinux.org/index.php/Bash/Prompt_customization
- https://medium.freecodecamp.org/how-you-can-style-your-terminal-like-medium-freecodecamp-or-any-way-you-want-f499234d48bc
Top comments (0)