Complex Color Patterns for Shell Prompts
Letter-level alternating colors for bash and zsh shells.
Posted on April 1, 2021
It's My Birthday!
No, that's not an April Fool's joke, and yes, I've heard them all before, har, har, har 😑.
Anyway, I typically like to make a nice little blog post on my birthday. My previous birthday posts have included a post about giving up as a creator and that I was shutting down the blog (which is obvious to see at this point was an April Fool's joke).
Colored Shell Prompts?! With Emojis?!
Most of us devs know we can color our shell prompts with various colors, and in shell syntax it is some sort of ugly looking formatting string like \e[31m
- that one is for the color red, which I'm sure you had memorized and knew right away, right? 😂
Well, I took a deep dive recently on the whole shell prompt formatting story recently, after creating my Full Stack Course "Bash Commands and Scripting - from Beginner to Expert":
All that aside, what if I told you that you could style your prompt in an advanced fashion, to make it look something like this:

or this:

or, my current setup, like this:

The Repository
The repository is here. There you'll find all the details about the actual color implementation and the steps you need to take to get these cool colors to show up in your shell!
As far as I know, I'm the first person to ever have done this! (Or at least published it) 😎 I know why now - because bash and zsh syntax makes creating such color patterns a massive headache! 😅
I believe I've saved you that headache by creating a repository for the snippets and have also pasted the code snippets below.
The Code
The repository is here. There you'll find all the details about the actual color implementation and the steps you need to take to get these cool colors to show up in your shell! For the impatient, a working script for both bash and zsh shells is below, but I can't promise that these following snippets are the most up-to-date versions.
bash
function buildColorPrompt() {# I always like showing what directory I am in (special character "\w" in PS1) - store the equivalent in this 'directory' variabledirectory=$(pwd)# Modify these to whatever you'd like!PROMPT_TEXT="awesome-shell-prompt-colors@awesome-machine [$directory] "# Colors seperated by comma - acceptable values are:# black, white, red, green, yellow, blue, magenta, cyan, light gray, light red, light green, light yellow, light blue, light magenta, light cyanPROMPT_COLORS="red,white,blue"# Colors!BLACK="\e[30m"WHITE="\e[97m"RED="\e[31m"GREEN="\e[32m"YELLOW="\e[33m"BLUE="\e[34m"MAGENTA="\e[35m"CYAN="\e[36m"LIGHT_GRAY="\e[37m"DARK_GRAY="\e[90m"LIGHT_RED="\e[91m"LIGHT_GREEN="\e[92m"LIGHT_YELLOW="\e[93m"LIGHT_BLUE="\e[94m"LIGHT_MAGENTA="\e[95m"LIGHT_CYAN="\e[96m"# End formatting stringEND_FORMATTING="\[\e[0m\]"# split PROMPT_COLORS into arraycount=0IFS=','for x in $PROMPT_COLORSdocolors_array[$count]=$x((count=count+1))doneunset IFS# break PROMPT_TEXT into character arrayletters=()for (( i=0 ; i < ${#PROMPT_TEXT} ; i++ )) {letters[$i]=${PROMPT_TEXT:$i:1}}# build prompt with colorscolor_index=0ps1='\['for (( i=0 ; i < ${#letters[@]} ; i++ )) {# Determine color in this giant case statementcolor="${colors_array[color_index]}"case $color in"black")COLOR=$BLACK;;"red")COLOR=$RED;;"green")COLOR=$GREEN;;"yellow")COLOR=$YELLOW;;"blue")COLOR=$BLUE;;"magenta")COLOR=$MAGENTA;;"cyan")COLOR=$CYAN;;"light gray")COLOR=$LIGHT_GRAY;;"dark gray")COLOR=$DARK_GRAY;;"light red")COLOR=$LIGHT_RED;;"light green")COLOR=$LIGHT_GREEN;;"light yellow")COLOR=$LIGHT_YELLOW;;"light blue")COLOR=$LIGHT_BLUE;;"light magenta")COLOR=$LIGHT_MAGENTA;;"light cyan")COLOR=$LIGHT_CYAN;;"white")COLOR=$WHITE;;*)COLOR=$WHITE;;esac# add to ps1 var - color, then letter, then the end formatterps1+=$COLOR"${letters[$i]}"# reset color index if we are at the end of the color array, otherwise increment itif (( $color_index == ${#colors_array[@]} - 1 ))thencolor_index=0else((color_index=color_index+1))fi}ps1+="$END_FORMATTING\]"# Finally: set the PS1 variablePS1=$ps1}# Set the special bash variable PROMPT_COMMAND to our custom functionPROMPT_COMMAND=buildColorPrompt;
zsh
function buildColorPrompt() {# I always like showing what directory I am indirectory=$(pwd)# Modify these to whatever you'd like!PROMPT_TEXT="youruser@yourmachine [$directory]"# Comma seperated colors - as many or as few as you'd likePROMPT_COLORS="15"# This will be the color of everything in the input part of the prompt (here set to 15 = white)PROMPT_INPUT_COLOR="15"# split PROMPT_COLORS into arraycolors_array=("${(@s/,/)PROMPT_COLORS}") # @ modifier# break PROMPT_TEXT into character arrayletters=()for (( i=1 ; i < ${#PROMPT_TEXT}+1 ; i++ )) {letters[$i]=${PROMPT_TEXT:$i-1:1}}# build prompt with colorscolor_index=1ps1=""for (( i=1 ; i < ${#letters[@]}+1 ; i++ )) {# Determine color in this giant case statementcolor="${colors_array[color_index]}"# add to ps1 var - color, then letter, then the end formatterps1+="%F{$color}${letters[$i]}"# reset color index if we are at the end of the color array, otherwise increment itif (( $color_index == ${#colors_array[@]} ))thencolor_index=1else((color_index=color_index+1))fi}# end color formatingps1+="%F{$PROMPT_INPUT_COLOR} %# "# Finally: set the PROMPT variablePROMPT=$ps1}# set the precmd() hook to our custom functionprecmd() {buildColorPrompt;}
You'll also find these snippets under the devops section of the snippets page.
Go ahead and paste these right into your .bash_profile
or .zprofile
, respectively, depending on what terminal you are using. Or, make a pull request on the repository to submit the code for a new shell!
Thanks!
That's all for now. I'm off to enjoy my birthday, but I may at some point write an additional post with a walkthrough of both functions - as it turns out, there are some annoying and interesting differences between bash and zsh - the most unforgivable is that loops in zsh start at 1 🙄.
Cheers! 🍺
Chris