Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

Color Your Shell Prompt Red If the Last Command Threw an Error


We'll cover examples that work with both bash and zsh. We'll go with red for errors and your default color for non-errors.

Quick Jump: Configuring your Prompt | Demo Video

Before we jump into the solution, here’s a brief primer on exit codes because it will be important to know about this when looking at the solution.

A standard Unix pattern is to have commands return a non-zero exit code when they fail or throw an error. For example using exit 1 is very common for errors but you’ll often see other numbers too for specific types of errors. When a command is successful it’ll exit 0.

Your shell allows you to reference $? which stores the exit code of the last run command. You can run echo $? to check it out.

Here’s a few examples:

# The whoami command returns the name of the user who ran the command.
$ whoami

$ echo "$?"

# On my machine abc123 isn't a valid command.
$ abc123
zsh: command not found: abc123

$ echo "$?"

In this case it’s pretty clear the abc123 command threw an error because zsh reported the command wasn’t found but other tools don’t always provide error messages.

For example echo hello | grep hi provides no output but grep failed because no match was found. In this case echo $? will return 1.

Now with grep it’s pretty clear something went wrong because you have no results but with other commands it’s not always clear, especially if you don’t know how the tool works ahead of time.

Wouldn’t it be nice to visually see that without needing to manually check the exit code?

Yes it would be and we can do that by coloring up your prompt to be red if the last command failed and then use your default color when it’s successful. Typically you’d color up the $ character or whatever character you’ve chosen to break up your prompt’s information with the command you’re running but you can do whatever you want.

Configuring your Prompt

We’ll go over examples for both zsh and bash and in both cases it will work out of the box without any additional plugins or extra functions.

In both cases you can experiment by copy / pasting these prompts into your current shell to tweak things to your liking and then when you’re happy you can place them into your .zshrc or .bashrc file so they persist.



PROMPT='%B%{$fg[green]%}%n@%{$fg[green]%}%M %{$fg[blue]%}%~%{$fg[yellow]%}%{$reset_color%} %(?.$.%{$fg[red]%}$)%b '

The important part for this post is %(?.$.%{$fg[red]%}$) which is near the end of the line. There’s a lot going on in this short amount of code.

%(?.YAY.NAY) is the general pattern for the above where YAY will run if the last run command was successful and NAY will run if it failed.

With that said, $ is the YAY case in our prompt which will output $ using whatever color you set previously (your default color). Then %{$fg[red]%}$ is the NAY case which does the same thing except uses a red $.

If you wanted to see the exit code on error you could use %(?.$.%{$fg[red]%}[%?]$). It’s doing the same thing as before except now it also includes [%?] where %? shows the exit code too. Now on error your prompt will show nick@kitt ~/src/github/dotfiles [127] $.


We’ll focus only on coloring up the $. Everything else about the prompt has been replaced with ... to show your user and path, etc..


PS1="... \$([ \$? == 0 ] && echo '$' || echo '\e[01;31m$') \e[00m"

The overall strategy is the same as zsh except we’re using a shell if condition that fits nicely on one line.

In this case we’re looking at $? to see if it’s 0. If so then we can output a default color $, otherwise we make a red $. We’re using ANSI colors for this since Bash doesn’t have human named color variables out of the box. 01;31m sets the foreground bright red and 00m ensures any custom colors get reset back to their default color.

We also need to escape $ in a few spots so that everything in the $() gets evaluated whenever PS1 is used instead of immediately when your bashrc file is loaded. I saw this trick referenced here https://stackoverflow.com/a/44214096.

The video below goes into a bit more details about everything.

Demo Video


  • 1:11 – A quick primer on checking the exit code of the last run command
  • 2:12 – Taking a look at the solutions
  • 3:40 – zsh solution
  • 5:27 – Optionally include the error code number in your prompt
  • 7:05 – bash solution

Have you configured your prompt to do this? Let me know below.

Never Miss a Tip, Trick or Tutorial

Like you, I'm super protective of my inbox, so don't worry about getting spammed. You can expect a few emails per month (at most), and you can 1-click unsubscribe at any time. See what else you'll get too.