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:
print_before_the_prompt () { echo "comes before the prompt" } PROMPT_COMMAND=print_before_the_prompt
If you use this, you shouldn’t see a difference in your prompt from what we have above. Now, let’s make this useful.
print_before_the_prompt () { echo "$USER: $PWD" } PROMPT_COMMAND=print_before_the_prompt PS1='->'
Here’s what you’ll get:
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 %s
s in the “template” string, and two other parameters. These will be placed into the string where the %s
s 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:
txtblk='\e[0;30m' # Black - Regular txtred='\e[0;31m' # Red txtgrn='\e[0;32m' # Green txtylw='\e[0;33m' # Yellow txtblu='\e[0;34m' # Blue txtpur='\e[0;35m' # Purple txtcyn='\e[0;36m' # Cyan txtwht='\e[0;37m' # White bldblk='\e[1;30m' # Black - Bold bldred='\e[1;31m' # Red bldgrn='\e[1;32m' # Green bldylw='\e[1;33m' # Yellow bldblu='\e[1;34m' # Blue bldpur='\e[1;35m' # Purple bldcyn='\e[1;36m' # Cyan bldwht='\e[1;37m' # White unkblk='\e[4;30m' # Black - Underline undred='\e[4;31m' # Red undgrn='\e[4;32m' # Green undylw='\e[4;33m' # Yellow undblu='\e[4;34m' # Blue undpur='\e[4;35m' # Purple undcyn='\e[4;36m' # Cyan undwht='\e[4;37m' # White bakblk='\e[40m' # Black - Background bakred='\e[41m' # Red badgrn='\e[42m' # Green bakylw='\e[43m' # Yellow bakblu='\e[44m' # Blue bakpur='\e[45m' # Purple bakcyn='\e[46m' # Cyan bakwht='\e[47m' # White txtrst='\e[0m' # Text Reset
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!
print_before_the_prompt () { printf "\n $txtred%s: $bldgrn%s \n$txtrst" "$USER" "$PWD" }
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.
So, now let’s add this to our prompt:
print_before_the_prompt () { printf "\n $txtred%s: $bldgrn%s $txtpur%s\n$txtrst" "$USER" "$PWD" "$(vcprompt)" }
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.
Moving On!
Here’s our complete .bashrc
or .bash_profile
file:
export PATH=~/bin:$PATH txtblk='\e[0;30m' # Black - Regular txtred='\e[0;31m' # Red txtgrn='\e[0;32m' # Green txtylw='\e[0;33m' # Yellow txtblu='\e[0;34m' # Blue txtpur='\e[0;35m' # Purple txtcyn='\e[0;36m' # Cyan txtwht='\e[0;37m' # White bldblk='\e[1;30m' # Black - Bold bldred='\e[1;31m' # Red bldgrn='\e[1;32m' # Green bldylw='\e[1;33m' # Yellow bldblu='\e[1;34m' # Blue bldpur='\e[1;35m' # Purple bldcyn='\e[1;36m' # Cyan bldwht='\e[1;37m' # White unkblk='\e[4;30m' # Black - Underline undred='\e[4;31m' # Red undgrn='\e[4;32m' # Green undylw='\e[4;33m' # Yellow undblu='\e[4;34m' # Blue undpur='\e[4;35m' # Purple undcyn='\e[4;36m' # Cyan undwht='\e[4;37m' # White bakblk='\e[40m' # Black - Background bakred='\e[41m' # Red badgrn='\e[42m' # Green bakylw='\e[43m' # Yellow bakblu='\e[44m' # Blue bakpur='\e[45m' # Purple bakcyn='\e[46m' # Cyan bakwht='\e[47m' # White txtrst='\e[0m' # Text Reset print_before_the_prompt () { printf "\n $txtred%s: $bldgrn%s $txtpur%s\n$txtrst" "$USER" "$PWD" "$(vcprompt)" } PROMPT_COMMAND=print_before_the_prompt PS1='->'
Well, that’s a crash-course on customizing your bash prompt. If you have any questions, be sure to drop them in the comments!
Comments