Configuring macOS command line
Tags: terminal, shell, zsh, ohmyzsh
Published: 2022-11-07 12:57:44

If you are serious about doing any kind of development work, it is really important to have an easy to use command line interface. Out of the box, macOS comes with the Terminal app. We will start from there and try to improve overall experience.

Before taking a deeper dive, take a look at the image below to get a glimpse of what is going to be covered here.

![Terminal app - configured terminal window](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3otf1062hfyyft1rknq2.png)

There will be plenty of things that can be changed and you can end up with completely different interface, if you choose so.

## Shell setup

Before going any further, you need to choose which shell to use. There are many out there and macOS usually comes with two of them pre-installed, `bash` and `zsh`.

My choice here is `zsh`. It is highly customisable and comes with many [powerful features](https://github.com/hmml/awesome-zsh). Even if you currently use `bash`, switching to `zsh` is quite simple. More so, `zsh` is an extended version of `bash`. They basically share a lot of common functionality and features.

### Install Zsh

Majority of macOS versions already come with `zsh` pre-installed. To check if `zsh` is installed on your system, run the following command.

```bash
zsh --version
```

If you have `zsh` installed, it's version should be printed out. In this case, you do not need to do any additional changes.

However, if `zsh` is not installed, you can easily install it using `homebrew`. Homebrew is a macOS package manager that makes it easy to install missing software. It usually comes pre-installed on many macOS versions. To install `zsh` using `homebrew`, run the following command.

```bash
brew install zsh
```

You can confirm if it's installed by running the `zsh --version` command again.

### Zsh as a default shell

Depending on the macOS version, your default shell might be set to `bash`. You can easily check it by running the following command.

```bash
echo $0
```

If you see that the output is `zsh`, then your default shell is already set properly. In case you need to set `zsh` as a default shell, do so by running the following command.

```bash
chsh -s $(which zsh)
```

Finally, start new shell session (close the current and open a new Terminal window), for the changes to take effect.

### Migrate from bash

If you are coming from `bash`, you might have some custom configuration saved in your `.bash_profile` or `.bashrc` files. Since those files are `bash` specific, they will not be used by `zsh` and all configuration saved in them must be migrated into [zsh specific files](https://zsh.sourceforge.io/Intro/intro_3.html).

- `.zshenv` is sourced on all shell invocations. Here you should save all exports that are needed for other programs.
- `.zshrc` is sourced when running in interactive shells. Here you can put all configs that make the shell experience more enjoyable, like: _aliases_, _functions_, _options_, etc.

Make sure that all of your `$PATH` exports are saved in the `.zshenv` file, since it will be sourced on every shell invocation.

## Oh My Zsh framework

When you switch to `zsh`, installing [Oh My Zsh](https://ohmyz.sh/) is one single thing that you must do. This will make your shell really awesome!

Oh My Zsh is a community driven framework for managing `zsh` configuration. Installing it could not be simpler, just run the following command.

```bash
sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
```

Oh My Zsh install command assumes that you already have **git installed** on your machine. In case you don't, follow [this guide](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) to install it.

Oh My Zsh will save it's configuration into the `~/.zshrc` file. In case you already had `.zshrc` created before, it's content will be copied and saved in `~/.zshrc.pre-oh-my-zsh` file.

You can move your previous configuration back to the `~/.zshrc` by copying it from `~/.zshrc.pre-oh-my-zsh`.

It is usually a good idea to create `~/env.sh` where you can keep your custom configuration. Then in `~/.zshrc` you can use the `source` command to load it.

```bash
...

# Load evn.sh file
source ~/env.sh
```

This ensures that your custom configuration will always be sourced when running shell in interactive mode. When you need to add or change custom configuration, just do it in the `env.sh` file.

### Themes

Your shell might be powerfull now, but it is not good enough if it looks ugly. Luckily, setting a theme with Oh My Zsh is a quite simple.

Open `~/.zshrc` file in your favorite editor, `vim` of course. In there, you will find a variable with the name `ZSH_THEME`. By default, it will be set to `robbyrussel`. To change the theme, just provide a different theme name.
 
There are tons of already pre-made [themes](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes) available to pick from.

Personally, I use the `arrow` theme since it provides simple, minimal and clean interface. To enable the `arrow` theme just set `ZSH_THEME="arrow"` in your `~/.zshrc` file. Make sure to restart your shell session after.

```bash
...

# Set name of the theme to load --- if set to "random", it will
# load a random theme each time oh-my-zsh is loaded, in which case,
# to know which specific one was loaded, run: echo $RANDOM_THEME
# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
ZSH_THEME="arrow"

...
```

You can also use [external themes](https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes) which are created by the community. Using external themes requires more work since they need to be added to the custom theme directory. You can follow [this guide](https://github.com/ohmyzsh/ohmyzsh/wiki/Customization#overriding-and-adding-themes) for more information about this topic.

### Plugins

Great thing about Oh My Zsh is that it **comes bundled** with all [kinds of plugins](https://github.com/ohmyzsh/ohmyzsh/wiki/plugins). This allows you to easily extend the functionality of your shell, just by enabling them. Plugins can be easily enabled in the `~/.zshrc` file by changing the `plugins` variable.

One such bundled plugin is called `web-search`. It allows you to query popular services, like google, from your terminal window. To enable this plugin, just add `web-search` to the `plugins` variable.

```bash
...

# Which plugins would you like to load?
# Standard plugins can be found in $ZSH/plugins/
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(web-search)

...
```

Keep in mind that `plugins` variable is actually an array. If you have multiple values inside, they must be separated with empty space.

Now, let's switch to **third party plugins**, since there are so many good ones. To use third party plugins you need to install them into the `$ZSH_CUSTOM/plugins` directory. After that, the only thing that needs to be done is to add the plugin, by it' name, into the `plugins` variable.

I would recommend installing following plugins since they can increase your shell productivity significantly.

- `zsh-autosuggestions` - suggests commands as you type based on history and completions.
- `zsh-syntax-highlighting` - highlights commands while you type them in the interactive terminal.

Install `zsh-autosuggestions` running following command.

```bash
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
```

Install `zsh-syntax-highlighting` running following command.

```bash
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
```

When plugins are installed, enable them via `plugins` variable and restart your shell for effects to take place.

```bash
...

# Which plugins would you like to load?
# Standard plugins can be found in $ZSH/plugins/
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(web-search zsh-autosuggestions zsh-syntax-highlighting)

...
```

Plugins can provide a lot of value and extend your shell in so many ways, but there is also one downside. Every plugin you add will **impact shell performance** and **startup time**. So, choose plugins wisely and keep only the ones you are actually using.

## Terminal app

This section is all about configuring, default, Terminal app that come preinstalled on every macOS.

You might wonder, why not use more feature rich apps like [iTerm2](https://iterm2.com/)?
The reason for me is really simple, I just do not use much of the provided features and the benefits for me are not that big.

With that out of the way, let's configure the Terminal app.

### Install Fira Code font

I have tried a lot of fonts in the terminal environment, but this one just feels the best. It is a completely free, monospaced font, containing [ligatures](https://github.com/tonsky/FiraCode#fira-code-free-monospaced-font-with-programming-ligatures) for common programming multi-character combinations.

Fastest way to install the font is to go to the [releases page](https://github.com/tonsky/FiraCode/releases) of the Fira Code repository and download the latest version. Once downloaded, you can just install all fonts provided in the `ttf` directory. With that done, Fira Code is installed onto your system.

### Custom profile

In the Terminal app, profiles can define custom configuration and behavior. To modify customization to our liking, a custom profile needs to be created.

It is totally fine to customize it manually, but there are also a lot of third party themes that can be used in the Terminal app. One example is the [Dracula theme](https://github.com/dracula/terminal-app). Usually, third party themes will be provided via `.terminal` file which can be imported in the Terminal app.

I personally use the Dracula theme myself. You can download `.zip` from [official website](https://draculatheme.com/terminal). It should come with the `Dracula.terminal` file.

To install it, open the Terminal app and go to _Preferences > Profiles_. From there, click on the _More_ icon and a dropdown will be shown where you need to select _Import_. When the theme is imported, it will be saved as a new profile with the name `Dracula`.

Make sure that `Dracula` profile is selected. On the bottom, you should see the _Default_ button. Click on the button and it will set, currently selected, profile as default. With this, when the new Terminal window is open, it will automatically use selected profile.

On the right side, you can see all the settings that can be changed. Since we use the Dracula theme, most of the settings does not need to be changed, but I like to tweak some of the options to make it more nice.

Let's start with **Background** settings. Click on the _Background icon_ and a new window should open. Here you can configure Terminal background settings. I like to keep it simple, so for me, settings are set to following.

```text
Background color   black (#000000)
Opacity            90%
Blur               5%
```

This will give you a Terminal window that is slightly transparent with a blurred background. I like it since it looks clean and opacity is high enough so underlying windows are not visible that much.

Next, the **Font** needs to be changed. Click on the _Change_ button under the _Font_ section and the new window should open. Select **Fira Code** as your font and adjust settings to your linking.

You can also tweak other settings as well, but I do not change them since they are defined by the Dracula theme anyways.

## Conclusion

Some people find working with terminal and command line tools very hard and often are trying to avoid it completely. But the truth is, **it is inevitable**.

When things are like that, why don't we make sure that the command line environment looks nice and actually help us to increase our productivity?

By choosing the right terminal app, changing shell and tweaking theme configuration it is possible to enhance command line experience drastically. I really hope that this post has given you a glimpse into what is possible and, at the end, you are able to customize your command line environment to your liking.