Your command line prompt is likely the part of your Linux terminal you interact with the most. Being able to customize it to suit your needs and preferences can greatly improve your productivity and experience when working in the shell.
In this comprehensive guide, we‘ll explore the ins and outs of customizing your PS1 bash prompt. Whether you‘re looking to add some color, include useful system information, or just make it look nice, we‘ve got you covered. Let‘s dive in!
What is PS1?
PS1 stands for "primary prompt string 1". It is an environment variable that controls what your command line prompt looks like in bash and other Bourne-compatible shells.
The value of PS1 can contain regular text and special escape sequences that print dynamic information when your prompt refreshes. Things like the current username, hostname, working directory, and more.
Here‘s what a default PS1 value might look like:
\u@\h \w\$
This would print something like:
john@server ~/projects$
When you customize your PS1, you are changing the value of this variable to control precisely what your prompt renders.
Common Escape Sequences
As mentioned above, escape sequences allow you to print dynamic information in your prompt. Here are some commonly used ones:
Sequence | Description | Example |
---|---|---|
\u | Username | john |
\h | Hostname | server |
\W | Current working directory basename | projects |
\w | Current working directory full path | /home/john/projects |
\d | Date | Tue Jan 10 |
\t | Time (24h) | 18:30 |
\T | Time (12h) | 06:30PM |
! | History number of this command | 782 |
# | Command number of this command | 2 |
There are many more available – check the bash man pages for a full list.
Now let‘s look at some examples of customizing PS1!
Example 1: Adding Color
One of the most common customizations is adding color. This helps visually distinguish parts of your prompt and make key information stand out.
Here‘s an example prompt with color:
export PS1="[\[\e[1;36m\]\u\[\e[m\]@\[\e[1;32m\]\h\[\e[m\] \W]\$ "
Breaking this down:
\[\e[1;36m\]
– Enables bold cyan text\[\e[1;32m\]
– Enables bold green text\[\e[m\]
– Disables formatting
So this will print the username in bold cyan, host in bold green, basename in default terminal color, and end with a $ in default color.
Result:
Much better! The username and host stand out visually, improving scannability.
Let‘s explore some more advanced color customizations next.
Example 2: Dynamic Colors
In addition to static colors, you can also dynamically change colors based on state. For example, you could print the time red if it‘s past 6PM:
export PS1="\[$(tput setaf 1)\]\A\[$(tput sgr0)\] | \[$(if [[ $(date +%k) -gt 18 ]]; then tput setaf 1; fi)\]\t\[$(tput sgr0)\] | \[\033[01;34m\]\u\[\033[00m\]@\[\033[01;32m\]\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ "
Here we are:
- Setting the time to red if past 6PM
- Printing the username in bold blue
- Printing the hostname in bold green
- Printing the working directory in bold blue
We are using some new escape sequences:
\A
– Time in 24-hour HH:MM formattput setaf 1
– Set text color to redtput sgr0
– Reset text formatting
Result:
As you can see, after 18:00 the time turns red automatically!
This is just one example – the possibilities with dynamic coloring are endless. You could color based on:
- Background jobs status
- Exit code of last command
- Current user / uid
- SSH connection status
- etc.
Next up, let‘s see how to integrate Git status information.
Example 3: Including Git Status
For developers or anyone working with Git, including repository status information directly in your prompt can be extremely useful.
Here‘s an example:
export PS1="\[$(tput setaf 3)\]\w\[$(tput sgr0)\]\[$(parse_git_branch)\] $ "
parse_git_branch() {
git branch 2> /dev/null | sed -e ‘/^[^*]/d‘ -e ‘s/* \(.*\)/ (\1)/‘
}
Breaking this down:
- We set the working directory to print in yellow
- Then call a
parse_git_branch
function that runsgit branch
to get the current branch name - We add this branch name in parentheses after the working directory
Result:
Now you can see what Git branch you are on directly in the prompt!
Some ideas for improvements:
- Color the branch red if the repo is dirty
- Show ahead/behind commit counts for remote branches
- Print an X if there are stashed changes
The possibilities are endless!
Next up, integrating with other tools…
Example 4: Docker and Kubernetes Integration
In addition to Git integration, you can also print status from other dev tools directly in your prompt.
For example, here is a prompt with:
- Current Kubernetes context
- Current Docker compose project (if applicable)
- Current Kubernetes namespace
export PS1="\u \[\e[32m\]\w\[$(parse_git_branch)\]\[$(tput sgr0)\] \[$(kube_ps1)\]\[$(docker_compose_ps1)\] \$ "
parse_git_branch(){
git branch 2> /dev/null | sed -e ‘/^[^*]/d‘ -e ‘s/* \(.*\)/(\1)/‘
}
kube_ps1(){
namespace=$(kubectl config view --minify=true -o "jsonpath={..namespace}")
context=$(kubectl config current-context)
echo -n "|\[$(tput setaf 245)\]$context\[$(tput sgr0)\]"
if [ -n "$namespace" ]; then
echo -n ":\[$(tput setaf 45)\]$namespace\[$(tput sgr0)\]"
fi
}
docker_compose_ps1(){
proj_running=$(docker compose ps -q 2>/dev/null)
if [ -n "$proj_running" ]; then
project=$(docker compose config --services)
echo -n " <\[$(tput setaf 153)\]$project\[$(tput sgr0)\]>"
fi
}
This shows:
my-context
– The active Kubernetes context in purplemy-namespace
– The active Kubernetes namespace in magenta (if non-default)my-services
– The running Docker Compose services in light yellow (if applicable)
Result:
This makes it easy to see your current environment at a glance!
Some ideas for improvements:
- Show Kubernetes pod status
- Print Docker image versions
- Include other tools like Terraform workspace, AWS profiles, etc
The same concept applies – shell out to the CLI for the tool and parse the output to include relevant info.
Example 5: Emojis and Font Awesome Icons!
In addition to text and colors, you can also spice up your prompt with emojis and icons.
Here‘s an example using Font Awesome:
export PS1="\[$(tput setaf 2)\]\uf085 \[$(tput setaf 7)\]\uf233 \[$(tput setaf 1)\]\uf09a\[$(tput sgr0)\] \[\e[1;34m\]\u\[\e[m\]@\[\e[1;34m\]\h \[$(tput sgr0)\]\w\$ "
Here we are printing icons for:
- House (directory)
- Heartbeat (system status)
- Battery (power status)
We could imagine replacing these with emojis or other icons to represent system state.
Result:
The possibilities here are endless – get creative with using visuals symbols to enhance your prompt!
Some ideas:
- Print weather emoji based on current temperature
- Change battery emoji level based on charge
- Print checkmark if background jobs are running
- Use emojis to represent connected devices/drives
Integrating Advanced Scripts and Functions
So far the customizations we‘ve shown rely solely on escape sequences and simple shell script snippets. But we can integrate much more advanced functions and even other scripts into our PS1.
For example, here is a prompt that displays the current song playing from Spotify using a python script:
export PS1="\[$(tput setaf 2)\]\j \[$(tput setaf 6)\]\u@\h \[$(tput sgr0)\]\w\[spotify\] \$ "
function spotify(){
if [[ -n $(pgrep spotify) ]]; then
artist=$(python ~/.config/spotify_song.py --artist)
track=$(python ~/.config/spotify_song.py --track)
echo -n " <\[$(tput setaf 2)\]$artist - $track\[$(tput sgr0)\]>"
fi
}
We are:
- Checking if Spotify is running with
pgrep
- Calling an external Python script to fetch the current song metadata
- Printing "artist – track" in the prompt
And here is an example that shows the unread count for your inbox using the gmail CLI:
export PROMPT_COMMAND=‘INBOX=$(gmailcli ls inbox --unread | wc -l); PS1="\u@\h \[\e[32m\]\w \[\e[31m\]$INBOX\[$(tput sgr0)\]";‘
We are:
- Running
gmailcli
to count unread emails - Saving count to $INBOX variable
- Printing the count in red in PS1
The key is you can include output from any scripting language into your prompt via $(command)
syntax.
Some other ideas:
- Print stock quotes
- Show currently playing YouTube/Netflix titles
- Display statuses from task/ticket systems
- Include notes from a notes app like Evernote/OneNote
The only limit is your imagination!
Optimizing Prompt Performance
One downside of advanced prompt customization is the potential performance hit, especially if using complex scripts. A fancy prompt won‘t do much good if it makes your terminal laggy!
Here are some tips for optimizing performance:
Use cache variables
Instead of running expensive commands every single time, cache the output in a variable that only updates every few seconds.
For example:
SPOTIFY_SONG=$(python ~/.config/spotify_song.py)
function update_spotify(){
SPOTIFY_SONG=$(python ~/.config/spotify_song.py)
}
export PROMPT_COMMAND="update_spotify; $PROMPT_COMMAND"
Use light-weight calls
Some commands like git branch
are faster than git status
. Profile commands to find optimal ones.
Limit rendering
Wrap prompts in a timer or conditional so they only render if recently updated:
if [[ $(date +%s) -gt $SPOTIFY_TIMER ]]; then
echo -n "$SPOTIFY_SONG"
fi
Delay initialization
If running on start slows your shell, lazily init after a few seconds:
sleep 5
export PROMPT_COMMAND=‘fancy_prompt‘
Simplify scripts
The more complex the integrations, the higher the performance cost. Simplify third-party scripts to just the essentials.
With some tweaking, you can build a performant prompt with minimal overhead.
Prompt Frameworks
While setting PS1 directly gives maximum flexibility, it does require managing the underlying logic yourself. Some prompt frameworks abstract this away for convenience.
For example:
- Starship offers 300+ prebuilt integrations and handles caching/optimization automatically.
- Oh My Bash has a theme marketplace with out-of-box prompts you can install.
- Tools like Powerlevel10k generate optimized PS1 code for you based on options.
The tradeoff is less customizability versus easier management. Evaluate both rolling your own PS1 vs using a framework for your needs.
And many frameworks allow replacing the final PS1 output anyway, giving a nice balance of convenience without fully sacrificing control.
Reusing and Sharing Prompts
Once you perfect your prompt, you likely want it consistent across all your machines without copying settings everywhere.
Some options for reusing prompts:
- Git Repo – Version and pull down your
.bashrc
- Dotfiles – Manage prompt alongside other dotfiles
- Gists – Great for snippet sharing
- Environment Files –
ps1.sh
file that sets PS1
And for inspiration:
- r/unixporn – Share and get ideas
- Bash Prompt Themes – Collections of user prompts
This way you can have a single prompt config without duplication.
Conclusion
Hopefully this guide has shown the immense possibilities (and fun!) in customizing your shell prompt with PS1.
Key takeaways:
- Use escape sequences like \u, \h and \w to print system info
- Integrate advanced scripts and external tools
- Optimize performance with caching, delays and simplification
- Check out prompt frameworks for easier management
- Share and reuse prompts across machines
A highly customized prompt can really up your productivity and command line game. Try out some of these ideas and see what works for your workflow!
Let me know in the comments if you have any other great prompt customization tips or tricks to share. Happy prompt building!