How to Customize Your Bash Prompt (PS1): Colors, Git Branch and More

Prompt · 7 min read · Updated 25 Oct 2026

On this page
  1. Try changes safely first
  2. PS1 escape codes
  3. Adding colors (and why \[ \] matters)
  4. Showing the current git branch
  5. Showing the exit status of the last command
  6. Building the prompt with PROMPT_COMMAND
  7. Two-line prompts
  8. PS2 and PS4
  9. Making it permanent
  10. Quick reference

Your prompt is the text Bash prints before every command. By default it is usually something like user@host:~/projects$, and it is controlled by one variable: PS1. With a few escape codes you can make it show the information you actually care about, such as the current directory, the git branch you are on, or whether the last command failed.

This guide walks through the building blocks, then puts them together into a prompt you can paste into your ~/.bashrc. If you would rather click than type, the Bash prompt generator builds a PS1 line for you.

Try changes safely first

Setting PS1 at the command line only affects the current shell, so it is safe to experiment. Close the terminal and everything goes back to normal. To see your current value:

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

To try a new one, assign it. Use single quotes so Bash stores the backslashes as typed:

$ PS1='\u in \w > '
alice in ~/projects > 

PS1 escape codes

Bash replaces special backslash sequences in PS1 each time it draws the prompt. These are the ones you will use most:

EscapeShowsExample
\uYour usernamealice
\hHostname up to the first dotweb01
\HFull hostnameweb01.example.com
\wCurrent directory, with ~ for home~/projects/site
\WOnly the last part of the current directorysite
\$# if you are root, otherwise $$
\tTime, 24-hour HH:MM:SS14:05:09
\ATime, 24-hour HH:MM14:05
\@Time, 12-hour with AM/PM02:05 PM
\dDateSun Oct 25
\jNumber of background jobs1
\!History number of this command512
\nNewline
\\A literal backslash\

The full list is in the Controlling the Prompt section of the Bash manual.

If \w gets too long in deep directories, set PROMPT_DIRTRIM=3. Bash then shows only the last three directory names, with ... in front.

Adding colors (and why \[ \] matters)

Terminals change colors when they receive ANSI escape sequences. In Bash you can write the escape character as \e, so \e[32m means "switch to green" and \e[0m means "reset to normal".

The important part: every color code must be wrapped in \[ and \]. These tell Bash that the characters inside take up no space on screen. Without them, Bash counts the invisible bytes as part of the prompt length, and long command lines wrap in the wrong place, overwrite the prompt, or leave garbage behind when you scroll through history.

$ PS1='\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]\$ '

That gives a bold green user@host, a bold blue directory, and normal text for what you type. Common codes:

CodeEffectCodeEffect
0Reset1Bold
30Black34Blue
31Red35Magenta
32Green36Cyan
33Yellow37White

Combine codes with semicolons, as in 1;31 for bold red. Most modern terminals also support 256 colors with \e[38;5;Nm, where N is 0 to 255; for example \[\e[38;5;208m\] is orange.

Always end with \[\e[0m\]. If you forget the reset, the color leaks into everything you type and into command output.

Showing the current git branch

Bash has no built-in escape for git, so you write a small function and call it from the prompt. This version uses git branch --show-current (git 2.22 and later), and falls back to a short commit hash when you are in a "detached HEAD" state. Outside a repository it prints nothing.

parse_git_branch() {
  local branch
  branch=$(git branch --show-current 2>/dev/null)
  if [[ -z $branch ]]; then
    branch=$(git rev-parse --short HEAD 2>/dev/null) || return 0
  fi
  printf ' (%s)' "$branch"
}

PS1='\u@\h:\w$(parse_git_branch)\$ '

On older git versions, replace the first command with git symbolic-ref --short HEAD, which does the same job.

Note the single quotes around the PS1 value. They keep $(parse_git_branch) from running once at assignment time; instead Bash runs it every time it draws the prompt, so the branch updates when you cd or switch branches. This works because the promptvars shell option is on by default.

Escape codes like \[ are processed before the function runs, so they do not work inside the function's output. Put the color codes around the $(...) in PS1, not inside the function. Git also ships a fuller script, git-prompt.sh, with a __git_ps1 function that shows dirty and staged state; many distributions install it with git.

Showing the exit status of the last command

Every command returns an exit status: 0 for success, anything else for failure. Seeing a red number when something fails is surprisingly useful. The catch is that $? changes as soon as anything else runs, including your git function. The clean solution is PROMPT_COMMAND.

Building the prompt with PROMPT_COMMAND

PROMPT_COMMAND holds a command that Bash runs just before it prints each prompt. If that command is a function that captures $? on its first line, you get the real status of what you just ran, and you can build PS1 with plain if logic:

__set_prompt() {
  local status=$?
  local reset='\[\e[0m\]' red='\[\e[1;31m\]' green='\[\e[1;32m\]'
  local blue='\[\e[1;34m\]' yellow='\[\e[33m\]'

  PS1="${green}\u@\h${reset}:${blue}\w${reset}${yellow}"'$(parse_git_branch)'"${reset}"
  if (( status != 0 )); then
    PS1+=" ${red}[${status}]${reset}"
  fi
  PS1+='\$ '
}
PROMPT_COMMAND=__set_prompt

After a failing command the prompt looks like this, with the [1] in red:

alice@web01:~/site (main) [1]$ 

The '$(parse_git_branch)' part is in single quotes on purpose: PS1 stores the literal text and Bash runs the function when it draws the prompt. Because the output of a command substitution is not expanded again, a strangely named branch cannot inject commands into your shell.

If something else (a tool like direnv, or your distribution) already sets PROMPT_COMMAND, add yours in front instead of replacing it, so it still sees the right $?:

PROMPT_COMMAND="__set_prompt${PROMPT_COMMAND:+; $PROMPT_COMMAND}"

Two-line prompts

When you work in long paths, a two-line prompt keeps your cursor at the same place on every line. Put the details on the first line and a short marker on the second, separated by \n:

$ PS1='\n\[\e[1;34m\]\w\[\e[0m\]$(parse_git_branch)\n\$ '

~/projects/website (main)
$ 

The leading \n adds a blank line before each prompt, which makes it easier to see where one command's output ends and the next begins.

PS2 and PS4

PS2 is the continuation prompt, shown when a command spans several lines (the default is > ). PS4 is printed in front of each line when you trace a script with set -x. A more useful PS4 shows the line number:

PS4='+ line ${LINENO}: '

Making it permanent

Once you like your prompt, add the function and the PS1 or PROMPT_COMMAND lines to the end of ~/.bashrc. Putting them at the end matters, because many distributions set their own PS1 earlier in that file. Then load the changes into the current shell:

$ nano ~/.bashrc
$ source ~/.bashrc

New terminals pick up the change automatically. If your prompt does not change in SSH logins, your system may be reading ~/.bash_profile instead; the .bashrc, aliases and functions guide explains which file runs when and how to make one source the other.

Test a new prompt in a second terminal before you close the first. A typo in ~/.bashrc will not lock you out, but it can make every new shell print errors, and it is easier to fix from a shell that still works.

Quick reference

  • PS1='\u@\h:\w\$ ': the classic user, host and path.
  • PS1='\W\$ ': minimal, current folder only.
  • PS1='[\t] \w\$ ': with a timestamp, handy for long-running work.
  • PROMPT_DIRTRIM=3: shorten long paths.
  • Wrap every color code in \[ \] and end with \[\e[0m\].
  • Use single quotes so $(...) runs each time the prompt is drawn.
  • Use PROMPT_COMMAND when you need $? or more complex logic.

Want to go further with the shell itself? The Bash keyboard shortcuts guide is a good next step.