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
TERMis set to something basic. Checkecho $TERM(xterm-256coloris 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.