Write Your Own Shell Prompt

Write Your Own Shell Prompt

Efficient and effective shell usage is maybe the greatest productivity multiplier for any developer, and it all starts with an effective prompt. There are tons of resources out there on how to build your own custom prompt, and more than a few tools that promise the best of prettiest layout. There are even several "prompt-in-a-box" utilites out there that will configure you prompt for you.

You should use these posts and tools as inspiration and then write your own.

Understand your prompt

I've had to help many developers understand issues with their prompts in the past. From issues like colors not showing up as expected to incredibly long wait times (one person's prompt took 8 seconds to load!), people who copy-paste configuration from around the internet tend to not understand what's happening when things go wrong.

Unnecessary information

I consider my prompt to be rather large. It contains information about my current working directory, the return code of the last command I ran, and, if I'm in a git repository, information about my current branch state. To better space out this amount of information, I split my prompt across 2 lines. This is a big prompt.

I actually read all the portions of my prompt. I know people who read none of their prompt and yet display all kinds of information in their prompt. People who regularly switch between different machines may want to display the hostname of the machine they're working on, but most people I see with these setups get in the habit of running hostname from their shell periodically to check the machine. Some people don't really care about seeing the whole path, only the last element. Some people don't work with version control software directly and don't want to see git status in the prompt. People on multi-user machines usually get good at running whoami. And many, if not most, people will never really care about the last return code.

The first step to a reasonable prompt is to decide what information you actually want to see every time you hit the enter key in your prompt, not downloading the most colorful package or plugin from someone with a very different workflow from yours.

Color codes

Stop using direct colors codes in your prompts. Please.

I see too many prompts that just inject a color into their prompt and it quickly makes things unreadable. While this may be desirable for posts trying to quickly demonstrate how a prompt can be configured, it leads to a mess of a prompt string. Can you tell what color this is?

\033]01;31\]

It's pink.

That was easy, but remember that prompt strings are filled with control characters. Let's say you have a pretty prompt and you'd like to include the last command's exit code in blue after the path element in your prompt. Find the place to make the change:

"\[\e[31m\][\[\e[m\]\[\e[38;5;172m\]\u\[\e[m\]@\[\e[38;5;153m\]\h\[\e[m\] \[\e[38;5;214m\]\W\[\e[m\]\[\e[31m\]]\[\e[m\]\\$ "
Taken from an otherwise good blog post on prompt configuration

Instead, customize your terminal application's colors. Every (reasonable) terminal emulator out there allows you to set the exact color you want each of the primary 16 colors to be. The bonus here is that other utilities in your terminal will pick up these colors so you don't have to worry about crazy color interactions between different themes in different programs.

Example of setting colors available in the MacOS Terminal application

Now that you have your terminal configured, you can make your shell prompt use those colors instead of guessing with control characters:

# bash
tput setaf 1

# zsh
{blue}

# fish
(set_color green)

You should read up a bit on how to manage colors with these patterns, but it makes it significantly easier to figure out what's going on in your prompt and why things appear the way they do.

Doing too much work

The single biggest problem I've seen with pre-built prompts in their integration with version control software. I'll use git as my example because it's the only one I have real familiarity with, but I know this problem exists for other systems. It can be extremely valuable to see what branch you're working on and how much work you've done relative to the remote.

The problem is that the human way of figuring this out is extremely inefficient for a machine. I know that in the past, oh-my-zsh would run git status and then parse the output to figure out what to display in the prompt. This is fine for most repositories, but I happened to be working on a very large repository at a company with extremely aggressive security software. git status could take 3 or 4 seconds to run, meaning it would take 3 or 4 seconds to get a prompt back. Every developer who used zsh would complain about how terrible it was to develop on the project, when in reality they were doing far too much work to figure out their repository state.

After some work, I found series of commands that would give me all the information in less than 100 milliseconds. While it did take me a fair bit of time to track down all the different plumbing commands in git and how they operate, I now have both a much better understanding of how git works and was able to help other people make their development environments more available.

config/fish/functions/fish_prompt.fish · main · Simon Swanson / Dotfiles
Configuration files for my workstations
My prompt configuration. See the git_fish_prompt function for the series of commands to generate a useful, yet fast, git prompt

Git is a very common culprit for slow prompts, but you shouldn't overlook other expensive operations. The 8 second prompt I mentioned earlier made 3 separate calls to report the status of an application. Don't put network calls in your prompt.

Security

I don't think this is a particularly big deal because all the prompt code I've seen online is non-nefarious, but it is something to think about at least a little bit. Would you notice if someone put a network call to record your last shell command in your prompt plugin? If you don't know that git status is being run under the hood, what else is going on that you're not aware of?

If you manage your own prompt command, you don't have to worry about this. You can worry about other things that probably won't ever happen, like someone hijacking your git command to send them copies of your repositories every time you make a change.

Making too many assumptions

I hate patched fonts, and I hate that utilities regularly require one to work.

This is certainly a place where you might disagree with my philosophy. To me, the shell is the basis of all interactions with my computer. When things go wrong, or I need to get something set up, I spin up a shell. The set of tool I need to get a working shell session should be as small as reasonably possible: a terminal emulator, my shell of choice, and my configuration files. Requiring a specific font or other tool is just to display a command prompt is, in my head, madness.


Conclusion, or something

Write your own prompt.

You'll learn what you actually care about, you'll know exactly what your dependencies are and why, and you'll come out of the experience with something that provides the most value to you every time you run a command.