Getting a Bash-like Prompt in Zsh

This entry is part 2 of 6 in the series Bash to Zsh

Apple recently announced that it’s moving the MacOS from the Bourne-again Shell (Bash) to the Z Shell (Zsh), and advised developers to make the change now, so they’re ready when they remove Bash altogether in some later version of the OS. Since I’m a big believer in not swimming up-stream, I decided to take their advice and switched to the Z Shell immediately.

The first thing I noticed was that the default prompt Apple provides for Zsh on their OS gives a lot less information than their default for Bash did. This is a sample of their old Bash prompt:

bart-imac2018:Documents bart$

That tells me the machine I’m on (bart-imac2018), the folder I’m in (Documents), and the username the shell is running as (bart), and whether or not I have super-user privileges ($ means no, # means yes). These are all very useful things, particularly when you SSH around a lot and su/sudo to different accounts. Also, IMO showing only the top-level folder rather than the full path gives a nice balance between the prompt getting too big, and not knowing where you are. I’ve never felt an urge to change the Mac’s default Bash prompt.

I can’t say the same about the Mac’s default Z Shell prompt! This is what I get on the same machine with the Z shell:

bart-imac2018%

It only shows the machine name (bart-imac2018) and whether or not I have super-user privileges (% for no, # for yes)!

Thankfully getting back to the old Bash-like prompt is easy — the TL;DR version is that you simply need to add the following line to your ~/.zshrc file:

PROMPT='%m:%1~ %n%# '

If you’d like to understand how exactly that works, and what other choices you have, read on!

Changing the Prompt

Like with Bash, your Zsh prompt is controlled using the PROMPT environment variable. You set the prompt using a formatting string where the % symbol indicates the start of a formatting variable that will get replaced by the appropriate value in the displayed prompt.

Let’s start with a really simple example that has no formatting variables — to set your prompt to boogers> simply execute the following:

PROMPT='boogers> '

You can do this safely because the change only applies to the current shell, so just open a new Terminal window to restore sanity!

There are lots of formatting variables you can include (you can see all of them in the relevant section of the Zsh docs), but the ones we’ll need are the ones for the computer name (AKA machine name), the current folder, and the current username:

Machine Name (%m or %M)

You probably just know your computer by it’s plain hostname (bart-imac2018 in my case), but it actually has a fully qualified domain name (bart-imac2018.localdomain in my case). We can show either in the Zsh prompt — the plain hostname is %m, and the fully qualified domain name (FQDN) is %M. On servers the FQDN might be useful, but on personal computers it rarely is, so to save space, I’d definitely recommend using %m. Also, the default Bash prompt on the Mac uses just the hostname too.

Current Folder (%/, %~, or %.)

If you want to see the full path to your shell’s present working directory you can use %/ (e.g. /Users/bart/Documents). If you want the full path, but shortened a little when possible, you can use %~, this will replace the path to your home directory with a ~ when ever possible (e.g. ~/Documents). Finally, if you just want to see the top-level current folder, you can use %. (e.g. Documents).

Username (%n)

The username is simple available via %n (for name).

Privilege Level (%#)

Whether or not the shell currently has super-user (root) privileges, if you do %# is replaced with a #, and if you don’t, with a %.

So, putting all that together, we can get back to the old Bash-style prompt with:

PROMPT='%M:%1~ %n%# '

Making the Change Permanent

Now that we know what we want to set our prompt to, how do we tell the Mac to set the prompt this way each time we open a new Terminal window? We need to add the command into one of Zsh’s startup scripts.

Zsh has many startup scripts, some always get executed, some only get execute for login shells, and some only for interactive shells. Since I only care about the prompt when I’m interactively typing into a shell, I want to add my change to the file that gets executed only for interactive shells. For Zsh that’s ~/.zshrc.

So, this is what my ~/.zshrc file now looks like:

# set the prompt to be bash-like
PROMPT='%m:%1~ %n%# '