The first thing I see every time I open a terminal is the prompt, and for years I just accepted whatever ugly default my distro shipped with. Eventually I got tired of a plain $ sitting there telling me nothing useful, so I dug into how Bash prompts actually work — and it turns out customizing them is one of the most satisfying small upgrades you can make to your daily workflow.
In this article, I’ll explain exactly how the Bash prompt system works, how to change colors, add useful information like git branches and exit codes, and how to make your changes stick permanently. I’ll go from the absolute basics to some more advanced tricks I use myself.
What Controls the Bash Prompt?
The Bash prompt is controlled by an environment variable called PS1 (Prompt String 1). There are actually four prompt variables:
PS1— the main prompt you see for every new command.PS2— the secondary prompt shown when a command continues onto a new line (usually>).PS3— used forselectmenus in scripts.PS4— used for debugging output when running scripts withbash -x.
For everyday customization, PS1 is what you’ll work with 95% of the time.
Checking Your Current Prompt
Before changing anything, see what you currently have:
echo $PS1
You might see something like:
\u@\h:\w\$
This is a string of special escape sequences that Bash expands into real values.
Understanding Prompt Escape Sequences
Here are the most useful ones:
| Sequence | Meaning |
|---|---|
\u | Current username |
\h | Hostname (up to first dot) |
\H | Full hostname |
\w | Current working directory (full path) |
\W | Current directory (basename only) |
\d | Date |
\t | Time (24-hour HH:MM:SS) |
\@ | Time in 12-hour AM/PM format |
\n | Newline |
\$ | Shows $ for regular users, # for root |
\! | History number of the command |
Setting a Simple Custom Prompt
Let’s try something basic:
PS1='\u@\h:\w\$ '
This is actually close to many defaults, but let’s build on it. Try this instead:
PS1='[\t] \u@\h:\w\$ '
Now your prompt shows a timestamp before your username, host, and current directory — useful if you’re tracking how long commands take between sessions.
Adding Color to Your Prompt
Colors make the prompt easier to scan visually, and they use ANSI escape codes. The general format is:
\[\033[COLOR_CODEm\]
Common color codes:
| Color | Code |
|---|---|
| Black | 30 |
| Red | 31 |
| Green | 32 |
| Yellow | 33 |
| Blue | 34 |
| Magenta | 35 |
| Cyan | 36 |
| White | 37 |
| Reset | 0 |
Here’s a colored version of the prompt:
PS1='\[\033[32m\]\u@\h\[\033[0m\]:\[\033[34m\]\w\[\033[0m\]\$ '
Let’s break this down:
\[\033[32m\]— starts green color for the username and hostname.\[\033[0m\]— resets color back to default.\[\033[34m\]— starts blue color for the working directory.\[\033[0m\]— resets again before the$symbol.
The \[ and \] brackets are important — they tell Bash that the enclosed characters don’t take up visible space, which prevents line-wrapping bugs where the cursor position gets miscalculated.
Adding Git Branch Information
One of the most useful things I added to my prompt was showing the current git branch when I’m inside a repository. Here’s a function that does it:
parse_git_branch() {
git branch 2>/dev/null | sed -n '/\* /s///p'
}
PS1='\u@\h:\w\[\033[33m\]$(parse_git_branch)\[\033[0m\]\$ '
How this works:
parse_git_branchrunsgit branch, silencing errors if you’re not in a git repo (2>/dev/null).sed -n '/\* /s///p'finds the line starting with*(the current branch marker) and strips it, printing just the branch name.- The function is called inside
PS1using$(...), so it’s re-evaluated every time your prompt renders.
Now, when I’m inside a git project, my prompt looks like:
user@hostname:~/projects/myapp (main) $
Making Your Prompt Permanent
Just like aliases, prompt changes made directly in the terminal only last for the current session. To make them permanent, add your PS1 line (and any functions it depends on) to ~/.bashrc:
nano ~/.bashrc
Add at the bottom:
parse_git_branch() {
git branch 2>/dev/null | sed -n '/\* /s///p'
}
export PS1='\[\033[32m\]\u@\h\[\033[0m\]:\[\033[34m\]\w\[\033[33m\]$(parse_git_branch)\[\033[0m\]\$ '
Reload it:
source ~/.bashrc
Multi-Line Prompts
If you want more information without cramming everything onto one line, use \n:
PS1='\[\033[36m\]┌── \u@\h \w$(parse_git_branch)\n\[\033[36m\]└─\$\[\033[0m\] '
This creates a two-line prompt with a decorative border, giving you space for details on the first line and a clean input area on the second.
Advanced: Showing Exit Codes
I like knowing immediately if my last command failed. Here’s how to show the exit status of the previous command:
PS1='\[\033[31m\]$(if [ $? -ne 0 ]; then echo "✗ "; fi)\[\033[0m\]\u@\h:\w\$ '
This checks $? (the exit code of the last command) and displays a red ✗ symbol if it was non-zero, meaning the previous command failed.
Real-World Use Cases
- Server identification: On production servers, I color the hostname red so I never accidentally run a risky command thinking I’m on a local machine.
- Virtual environment awareness: When working in Python, tools like
venvautomatically prepend the environment name to your prompt — you can replicate this manually for other tools. - Time tracking: Adding
\thelps me see exactly when long-running commands started and finished. - Team consistency: Some teams standardize prompt formats across
.bashrcfiles in shared dotfiles repositories so everyone’s terminal shows the same layout during pair programming or screen sharing.
Automation: Using a Prompt Framework
If building this manually feels like too much, tools like Starship (cross-shell) or Powerline offer prebuilt, highly configurable prompts. I still prefer hand-rolling my PS1 because it’s lightweight and doesn’t require installing anything extra, but these tools are worth knowing about if you want a fast, feature-rich starting point.
Best Practices
- Keep prompts informative but not cluttered — too much information defeats the purpose of a quick glance.
- Always wrap non-printing characters (colors) in
\[and\]to avoid cursor/line-wrap bugs. - Test new prompts in a temporary session before making them permanent, in case of syntax errors.
- Use
export PS1=...in.bashrcso the variable is available to subshells if needed.
Security Considerations
Be cautious with prompt functions that execute external commands (like parse_git_branch) since your prompt re-runs them constantly. Avoid embedding commands that could leak sensitive information into a prompt that might be visible during screen sharing or in terminal recordings.
Optimization Tips
If your prompt calls external commands like git, keep the logic lightweight, since it runs every time the prompt is drawn (i.e., after every command). A slow function will make your terminal feel sluggish. Caching results or checking for a .git directory before calling git branch can help:
parse_git_branch() {
if [ -d .git ] || git rev-parse --git-dir > /dev/null 2>&1; then
git branch 2>/dev/null | sed -n '/\* /s///p'
fi
}
Troubleshooting Common Issues
Cursor jumps to wrong position after typing long commands: This almost always means you forgot to wrap color codes in \[ and \].
Prompt reverts after closing terminal: You set PS1 directly in the shell instead of adding it to ~/.bashrc.
Git branch not showing: Make sure the parse_git_branch function is defined before it’s referenced in PS1, and that it’s also added to .bashrc.
Colors show as garbled text instead of actual colors: Your terminal emulator might not support ANSI color codes, or you’re missing the escape brackets.
Frequently Asked Questions
Will customizing PS1 break anything else in Bash? No, PS1 is purely cosmetic and doesn’t affect script behavior or command execution.
Can I use emoji in my prompt? Yes, most modern terminals support Unicode, so you can add emoji directly in your PS1 string.
Does this work the same way in Zsh? No, Zsh uses PROMPT or PS1 with a slightly different escape syntax (%n, %m, %~, etc.).
How do I reset my prompt to default? Comment out or remove your custom PS1 line in .bashrc and reload, or manually set PS1='\u@\h:\w\$ '.
Common Mistakes to Avoid
- Forgetting the trailing space after
\$inPS1, which makes commands run directly against the prompt symbol. - Not testing color codes before saving them permanently.
- Overloading the prompt with so much information it becomes hard to read at a glance.
- Hardcoding a username or hostname instead of using
\uand\h, which breaks portability across machines.
Summary
Customizing your Bash prompt is a small change that pays off every single day you use the terminal. Starting from the basic PS1 variable, you can add colors, directory paths, git branch info, and even exit status indicators — all while keeping things fast and readable. Once you’ve built a prompt you like, save it in ~/.bashrc so it’s there every time you open a new terminal.
References
- GNU Bash Manual — Controlling the Prompt: https://www.gnu.org/software/bash/manual/html_node/Controlling-the-Prompt.html
- Bash Manual (full): https://www.gnu.org/software/bash/manual/bash.html
