The shell prompt is the line you look at all day. A good prompt tells you where you are (which server, which directory, which user) at a glance, which prevents the classic mistake of running a command on the wrong machine. It’s all controlled by the PS1 variable.

PS1 basics

echo "$PS1"
PS1='\u@\h:\w\$ '

Common escape codes:

Code Shows
\u Username
\h Hostname (short)
\H Full hostname
\w Current directory (~ for home)
\W Last part of the directory
\$ # for root, $ for others
\t / \A Time (24h with seconds / HH:MM)
\n Newline
\j Number of background jobs

Changes made at the prompt last until you log out. Put them in ~/.bashrc to keep them. See .bashrc vs .bash_profile.

Adding colors

Colors use ANSI escape codes, wrapped in \[ … \], so bash knows they take no space (otherwise long lines wrap badly):

# 32 = green, 34 = blue, 31 = red, 33 = yellow, 0 = reset
PS1='\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]\$ '
Code Color
30–37 Black, red, green, yellow, blue, magenta, cyan, white
1; Bold
0 Reset
38;5;N 256-color palette number N

Make production and root obvious

A red prompt on production servers, or for root, is an effective safety measure:

# in ~/.bashrc
if [ "$(id -u)" -eq 0 ]; then
  PS1='\[\e[1;31m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]# '
else
  PS1='\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]\$ '
fi

Or use an environment label:

ENV_LABEL="PROD"
PS1='\[\e[41;97m\] '"$ENV_LABEL"' \[\e[0m\] \u@\h:\w\$ '

Give each server a clear hostname, too: web1-prod, not ubuntu-s-1vcpu. See change the hostname.

Show the last command’s exit status

PS1='$(e=$?; [ $e -ne 0 ] && printf "\[\e[31m\][%s]\[\e[0m\] " $e)\u@\h:\w\$ '

A red [1] appears when the previous command failed.

Show the git branch

Git ships a helper for this:

source /usr/lib/git-core/git-sh-prompt 2>/dev/null || source /usr/share/git-core/contrib/completion/git-prompt.sh
GIT_PS1_SHOWDIRTYSTATE=1
PS1='\u@\h:\w\[\e[33m\]$(__git_ps1 " (%s)")\[\e[0m\]\$ '

You’ll see (main*) inside repositories, with * for uncommitted changes.

Starship: a ready-made prompt

Starship is a fast prompt (written in Rust) that works in bash, zsh and fish, and shows git status, language versions, the exit code, and the command duration:

curl -sS https://starship.rs/install.sh | sh
echo 'eval "$(starship init bash)"' >> ~/.bashrc

Configure it in ~/.config/starship.toml. Symbols need a Nerd Font in your local terminal. Keep prompts lightweight on slow servers: anything that runs commands (git status in huge repos) adds delay to every prompt.

Window titles

Set the terminal tab title to user@host, which is helpful with many SSH sessions:

PS1="\[\e]0;\u@\h: \w\a\]$PS1"

Troubleshooting

  • Lines overwrite themselves or wrap oddly: a color code isn’t wrapped in \[ … \], so bash miscounts the prompt’s width.
  • Colors don’t appear: the terminal may not support them, or TERM is set to something basic. Check echo $TERM (xterm-256color is typical).
  • Prompt is slow: something in it runs a slow command. Remove parts until it’s fast again, or use Starship, which times out slow modules.

Quick reference

Element Code
user@host:path \u@\h:\w
Root/user sign \$
Color start / reset \[\e[1;32m\] / \[\e[0m\]
Git branch $(__git_ps1 " (%s)")
Make permanent Put PS1=… in ~/.bashrc

Related: zsh and Oh My Zsh and Linux terminal shortcuts.

  • Linux
  • Bash
  • Productivity