How to Customize the Command Prompt

I’m a big fan of the terminal: whether you’re leveraging a handful of commands (or more!) to improve your development process, or just using it to quickly move around your drives and open files and folders, the command line is an awesome tool. However, if you use it often, you’ll want to customize it to your needs. I'll show you how to do that today!

I'm often asked, "How did you get your command prompt to look like that?" Well, in this tutorial, I’ll show you exactly how to do it. It’s pretty simple, and won’t require too much of your time.

I should note that what I’m showing you is specifically for the bash shell; this is the default shell on Mac and most Linux systems. If you’d like a bash prompt on Windows, you might want to check out Cygwin.

How does it Work?

Before we get started, let’s talk for a minute about how you customize your bash prompt. It’s not quite the same as you’re average application: there’s no preferences panel. Your customizations are stored in a file. If you’re on Linux (or using Cygwin), that will be your .bashrc file; on Mac, that’s your .bash_profile file. In both cases, this file is kept in your home directory (if you aren’t sure where that is for a Cygwin install, run the command echo $HOME). Note that I’ll only refer to the .bashrc file from here on out, but use the .bash_profile if you’re on a Mac.

Note that on Macs (and possibly Linux machines; I’m not sure), files that begin with a period are hidden by default. To show them, run these two lines in the terminal

defaults write com.apple.finder AppleShowAllFiles TRUE
killall Finder

So, what goes in that .bashrc file? Each line is actually a command that you could run on the command line. In fact, that’s how these config files work: When you open the console, all the commands you’ve written in the config file are run, setting up your environment. So, if you just want to try out some of what I’ll show below, just type it on the command line itself. The simplicity here is beautiful.

Customizing PS1

Let’s start with a definition. The prompt is what you see at the beginning of the line, each time you hit enter on the command line. Here’s what the default settings are for the Mac:

In this case, the prompt is andrews-macbook:~ screencast$. There’s a few variables here: andrew-macbook is the name of this computer, ~ is the current directory (the home directory) and screencast is the username. Let’s customize this a bit.

Open up either your .bashrc file. The way we set what information is displayed in the prompt is with the PS1 variable. Add this to the file:

PS1='->'

Notice that I don’t put spaces on either side of the equals sign; that’s necessary. Save this file in your home directory and re-open a terminal window. Now, you should have a prompt that looks like this:

I’ll note here that if you find it tedious to close and re-open your terminal each time you make a change to your .bashrc or .bash_profile, there’s a bit of a shortcut: You can load any bash customization file with the source command. Run this in your terminal:

source ~/.bashrc

Still too long? Well, a single period (.) is an alias for source. Happy now? If you’re quick, you’ll realize that we can use the source command to include other files within our .bashrc file, if you want to split it up to keep in under control.

Let’s customize our prompt a bit more. We can use built-in variables in the string we assign to PS1 to include helpful information in the prompt; here’s a few useful one:

\d: Date

\h: Host

\n: Newline

\t: Time

\u: Username

\W: Current working directory

\w: Full path to current directory

So, if you set your prompt to this:

PS1='\n\W\n[\h][\u]->'

you should see something like this:

Notice a few things here: firstly, we’re using a bunch of the variables shown above to give us more information. But secondly, we’re including a few newlines in there, and getting a more interesting prompt: we have the current directory on one line, and then the actual prompt on the next line. I prefer my prompt this way, because I always have the same amount of space to write my commands, no matter how long the path to the current directory is. However, there’s a better way to do this, so let’s look at that now.

Customizing PROMPT_COMMAND

The better way to do this is the use the PROMPT_COMMAND variable; the contents of this variable isn’t just a string, like with PS1. It’s actually a command that executed before bash displays the prompt. To give this a try, let’s add this to our .bashrc:

PROMPT_COMMAND='echo "comes before the prompt"'

We’re using the echo command here; if you aren’t familiar with it, you just pass it a string, and it will write it to the terminal. By itself, it’s not incredibly useful (although you can use it to view variables: echo $PS1), but it’s great when used with other commands, so display their output. If you added the line above, you should see this:

Let’s do something more useful here. Let’s write a bash function that we will assign to PROMPT_COMMAND. Try this:

That’s a good start, but I want to do a bit more. I’m going to use the printf command instead of echo because it makes including newlines and variables a bit easier. A quick background on the printf command: it takes several paramters, the first being a kind of template for the string that will be outputted. The other parameters are values that will be substituted into the template string where appropriate; we’ll see how this works.

So let’s do this:

print_before_the_prompt () {
printf "\n%s: %s\n" "$USER" "$PWD"
}

See those %s parts in there? That means “interpret the value for this spot as a string”; for context, we could also use %d to format the value as a decimal number. As you can see, we have two %ss in the “template” string, and two other parameters. These will be placed into the string where the %ss are. Also, notice the newlines at the beginning and end: the first just gives the terminal some breathing room. The last one makes sure that the prompt (PS1) will be printed on the next line, and not on the same line as PROMPT_COMMAND.

You should get a terminal like this:

Adding Some Color

Looking good! But let’s take it one step farther. Let’s add some color to this. We can use some special codes to change the color of the text in the terminal. It can be rather daunting to use the actual code, so I like to copy this list of variables for the color and add it at the top of my .bashrc file:

There’s some method to this madness: The first set are turn on normal coloring. The second set turn on bold coloring. The third set turn on underlined coloring. And that fourth set turn on background coloring. That last one resets the coloring to normal. So, let’s use these!

Here, I’ve added $txtred before the first %s, and $bldgrn before the second %s; then, at the end, I’ve reset the text color. You have to do this because once you set a color, it will hold until you either use a new color or reset the coloring. You’ll also notice that when setting a variable, we don’t prefix it with a dollar sign; but we do use the dollar sign when using the variable: that’s the way bash variables work. This gives us the following:

Let’s move on to the final step: adding some scripting to give us even more information.

Adding Version Control Information

If you’ve seen the screencasts that come with my book Getting Good with Git, you might remember that I have some version control information showing in my prompt. I got this idea from the excellent PeepCode “Advanced Command Line” screencast, which share this, as well as many other great tips.

To do this, we’re going to need to download and build the script that finds this information. Head on over to the repository for vcprompt, a script that outputs the version control information. If you’re familiar with the Mercurial version control system, you can use that to get the repo, but you’ll most likely want to hit that ‘zip’ link to download the script code as a zip file. Once you unzip it, you’ll have to build the script. To do this, just cd into the unzipped script folder and run the command make. Once this command runs, you should see a file named ‘vcprompt’ in the folder. This is the executable script.

So, how do we use this in our prompt? Well, this brings up an important rabbit-trail: how do we “install” a script (like this one) so that we can use it in the terminal? All the commands that you can run on the terminal are found in a defined array of folders; this array is the PATH variable. You can see a list of the folders currently in your PATH by running echo $PATH. It might look something like this:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin

What we need to do is put the executable script vcprompt in a folder that’s in our path. What I like to do (and yes, I learned this trick from that PeepCode screencast, too) is create a folder called ‘bin’ (short for ‘binary’) in my home directory and add that folder to my PATH. Add this to your .bashrc:

export PATH=~/bin:$PATH

This sets PATH to ~/bin, plus whatever was already in the PATH variable. If we now put that vcprompt script into ~/bin, we will be able to execute it in any folder on the terminal.

I’ve added $txtpur %s to the “template” string, and added the fourth parameter"$(vcprompt)". Using the dollar sign and parenthesis will execute the script and return the output. Now, you’ll get this:

Notice that if the folder doesn’t use some kind of version control, nothing shows. But, if we’re in a repository, we get the version control system that’s being used (Git, in my case) and the branch name. You can customize this output a bit, if you’d like: check the Readme file that you downloaded with the source code for the vcprompt script.