DEV Community

Cover image for Customizing your shell
Balthazar Rouberol
Balthazar Rouberol

Posted on • Edited on

Customizing your shell

Originally posted on my blog.

This article is part of a self-published book project by Balthazar Rouberol and Etienne Brodu, ex-roommates, friends and colleagues, aiming at empowering the up and coming generation of developers. We currently are hard at work on it!

If you are interested in the project, we invite you to join the mailing list!

Table of Contents

Customizing your shell

It is very common for programmers to tweak and customize their terminal
and shell for hours, add or write new plug-ins, all in pursuit of the
“perfect environment” and an increase of productivity. Others, on the
contrary, avoid tweaking their shell altogether in order to always get
the same experience on every machine.

On a personal note, I tend to favor having a personalized shell as much
as possible. I feel that sharing files between different computers is
now a solved issue, and the benefits I get from having personalized my
work environments are so great that I gladly pay the small price of
synchronizing that configuration between my computers.

In that chapter, we will learn more about the shell and how to configure
your terminal environment to make it work for you. Please note that
some of the recommendations come from personal taste, and might not work
for you nor suit you. We encourage you to explore and find what feels
right, but we hope to at least nudge you in the right direction.

Which terminal should I use?

First off, if you are new to using the terminal, you might not have
realized that it exists multiple terminal applications. MacOS comes
with Terminal pre-installed, and most Linux distributions come with
either xterm, Gnome-terminal or Konsole pre-installed, and there is a
vast number of available alternatives.

I don't think there is a good, absolute and definitive answer when it
comes to picking the “right” terminal application. You might get various
answers depending who you ask. That being said, I can at least mention
my own personal recommendations and preferences.

Whatever terminal you end up using, I think that it is really important
you configure it to your liking and preferences. As a programmer, you
will probably spend a great deal of time in your terminal, and for you
to feel productive and empowered, it needs to work for you.

Terminator

If you are running Linux, I personally favor Terminator1 over the
default choices. It has several features I find useful:

  • a tab system, allowing you to have multiple tab of terminal(s) within the same window
  • a grid system, allowing you to have multiple terminals in the same tab

I can work in multiple panes within the same tab, and have one tab per project
I can work in multiple panes within the same tab, and have one tab per project

Here are the terminator keyboard shortcuts I find the most useful:

Shortcut Action
Ctrl - Shift - E split the screen vertically
Ctrl - Shift - O split the screen horizontally
Ctrl - Shift - T open a new tab
Ctrl - PageUp switch to the next tab
Ctrl - PageDown switch to the previous tab
Ctrl - N open a new window
Ctrl - Shift - + zoom in
Ctrl - Shift - - zoom out
Ctrl - D close the current terminal

iTerm2

As far as macOS is concerned, I find the default terminal (plainly named
Terminal) to be hard to use. The terminal that seems to be widely
accepted by the macOS programming community is iTerm22. It has all of
the features cited above, and many (many) more!

iTerm2 looks similar to Terminator but can do much, much more
iTerm2 looks similar to Terminator but can do much, much more

The iTerm2 keyboard shortcuts I find the most useful are:

Shortcut Action
Cmd - D split the screen vertically
Cmd - Shift - D split the screen horizontally
Cmd - T open a new tab
Cmd - Shift - + zoom in
Cmd - Shift - - zoom out
Cmd - N open a new window
Cmd - D close the current terminal

The following sections go over some non-default iTerm2 settings that I
find convenient. Again, these are my preference and are in no way
prescriptive. Feel free to discard them if you want.

Open file shortcut

One of the iTerm2 features I enjoy is the ability of using
Cmd + mouse click on a file path or an URL, to open the
resource with the default associated program. For example, it will open
an URL in your browser, a path to a local PDF file with Preview, a text
file with your preferred text editor, etc.

By enabling this feature, you will be able to open a file using a graphical application from your terminal
By enabling this feature, you will be able to open a file using a graphical application from your terminal

Intuitive location for new terminals

Another tweak I've done to iTerm2 was changing the working directory new
terminals will open into by default. What I wanted was

  • open a new terminal window in my home directory
  • open a new terminal tab in my home directory
  • open a new terminal split pane in the previous session's directory

I did this because I oftentimes found myself splitting the current tab
when I want to run multiple commands within the same project, and I had
to cd into the project directory every time I did a pane split.

I reduced the time I spent  raw `cd` endraw -ing into project directories with these settings. Preferences \> Profiles \> General \> Working Directory \> Advanced Configuration \> Edit
I reduced the time I spent cd-ing into project directories with these settings. Preferences > Profiles > General > Working Directory > Advanced Configuration > Edit

What font should I use?

Using a font you enjoy is paramount. If you spend a lot of time reading
and writing in your terminal, you might as well do it using a font that
feels right to you.

I personally really enjoy the Fira Code3 font, both in my text editor
and my terminal. Not only does it look really nice on the eye, but it
also contains a set of ligatures for multi character combinations,
such as ! and = rendered in a single character, allowing you to read
code and decode symbols more easily.

Example of rendered character ligatures
Example of rendered character ligatures

Note that not all terminals support fonts with ligatures. For example,
iTerm2 does but Terminator does not.

Note While Fira Code has my preference, there are other well-designed fonts
including ligatures, such as JetBrains Mono.4

What shell should I use?

We have hinted at it until now: bash is not the only shell out there.
You are free to use other shells if you want, such as zsh, fish,
nushell, … As it was the case with terminals, the “good” terminal
really depends on your definition of “good”. If you deeply care about
using the same shell on every machine you work on, then bash is
possibly for you. It has been around since 1989, is stable, mature and
is the default shell on almost5 every UNIX system out there.

When researching this book, I was surprised to learn that zsh (or the
Z-shell) wasn't really the last “kid on the block” either, as it was
first released in 1990, just a year after the first stable bash release!
You can expect the same level of stability, maturity and even syntax (to
a large extent, except when it comes to configuration) than bash.

I personally think zsh really shines by providing a powerful default
auto-completion experience, as well as more configuration options. As
zsh is compatible with bash's own syntax, I encourage you to try
them until you feel comfortable with one or the other.

The fish6 shell takes a radical turn from bash or zsh by
providing an incompatible but “simple and clean” syntax, an extremely
powerful command suggestion system, and an interactive configuration
wizard.

If you are getting started with using the shell, my personal
recommendation is to stick to bash or zsh and experiment with other
shells to see what value they bring once you feel more confident.

Changing your default shell

The chsh (standing for change shell) command allows you to change
your default shell.

Examples:

# Switching to bash by default
$ chsh -s /bin/bash
Enter fullscreen mode Exit fullscreen mode
# Switching to zsh by default
$ chsh -s /bin/zsh
Enter fullscreen mode Exit fullscreen mode

Once you have run chsh, any new terminal window you open will run your
new default shell.

Configuring your shell

Up until now, every example we have seen have defined environment
variables, aliases and functions directly in the shell. However, if we
closed that shell, all of these changes would be undone and we would
have to start again the next time we open a new one. Fortunately, all of
these settings can be persisted in a configuration file. Adding
aliases, environment variables and functions to that file will make sure
they get imported every time you open a new shell.

These files usually reside in your home directory, and are named
.bashrc for bash, and .zshrc for zsh.

$ cat ~/.zshrc
export EDITOR=vim
export PATH=$HOME/bin

alias ls='ls -G'
alias ..='cd ..'
alias ...='cd ../..'
alias filesize='ls --size --human-readable -1'

function mkcd {
    local target=$1
    mkdir -p $target
    cd $target
}
Enter fullscreen mode Exit fullscreen mode

After adding anything to your shell configuration file, you need to run
source ~/.zshrc (or source ~/.bashrc, depending on your shell). The
source built-in command reads and executes commands from the argument
file name in the current shell environment. Said in another way, running
source ~/.<file> will cause the shell to reload its configuration.

Note rc stands for run commands. Indeed, when you source your
configuration file, you will run the commands it contains. The subtlety
with source is that it executes the argument script within your
current shell, meaning any sourced commands will have a side-effect on
your running shell.

If you can never remember a given command's options, or if you always
find yourself typing a group of commands, I encourage you to define
aliases and functions in your shell configuration file. They will allow
you to feel more productive day after day, especially so if the alias
and tools are abstracting complex commands.

Note The previous chapter ended with some real-life examples of alias and
functions. Feel free to add them to your shell configuration file.

Configuring your prompt

Configuring your prompt is a very
good way to make the shell work for you as much as possible, by
providing you with useful context, such as the time of day, whether the
last command was successful, your current working directory… While they
can provide context and information to you, they will carry that context
to anyone you copy and paste a command and associated output to.

Configuring your prompt is done by changing the value of the PS1
environment variable.

$ export PS1="MY COOL PROMPT $"
MY COOL PROMPT $
Enter fullscreen mode Exit fullscreen mode

I think we can agree that MY COOL PROMPT is not as informative as it
could, so let's change it to put our prompt to work. As the prompt
configuration work slightly different between bash and zsh, we will
address both cases in two different sections.

Configuring your bash prompt

The PS1 environment variable can be defined by using a mix and match
of both regular and special characters. The regular characters are just
displayed as-is, whereas the backslash-escaped special characters are
interpreted by bash at the time PS1 is displayed and replaced by the
associated value. The most useful special characters are defined as
follows.

Character Meaning
\h The hostname up to the first dot
\t The current time, in 24-hour HH:MM:SS format
\u The current user's username
\w The full current working directory ($HOME rendered as ~)
\W The basename of the current working directory ($HOME rendered as ~)
\n A new line

These special characters are evaluated every-time the prompt is displayed to make sure you always get the most up-to-date context.

Note The PROMPTING section of the bash manual contains the full list of
backslash-escaped special characters.

Examples

$ export PS1='\u@\h \W $'
br@morenika ~ $
Enter fullscreen mode Exit fullscreen mode
$ export PS1='[\t] \u@\h \W $'
[13:33:55] br@morenika ~ $
Enter fullscreen mode Exit fullscreen mode
$ export PS1='[\t \u@\h:\w]\n>>> '
[13:57:55 br@morenika:~/code]
>>>
Enter fullscreen mode Exit fullscreen mode

Note You can use online tools such as ezprompt7 to try different
configurations until you find something you like.

Whatever PS1 value you settle with should be persisted and exported in
your .bashrc configuration file.

Configuring your zsh prompt

zsh exposes a bit more options than bash when it comes to prompt
configuration. Both PS1 and PROMPT environment variable can be set
to the same effect, if you find PROMPT more explicit.

Instead of being backslash-escaped, zsh's special characters are
prefixed by %, and are called prompt sequences. The most useful are
detailed here.

Sequence Meaning
%m The hostname up to the first dot
%* The current time, in 24-hour HH:MM:SS format
%n The current user's username
%~ The full current working directory ($HOME rendered as ~)
%1~ The basename of the current working directory ($HOME rendered as ~)
%? The exit status of the last command executed
%% A %
$'\n' A new line
%B (%b) Start (stop) bold font mode
%F (%f) Start (stop) using a given foreground color, if supported by the terminal

Note You will find the full list of prompt sequences in the zsh
documentation8.

Examples

$ export PROMPT='%n@%m %~ $ '
br@morenika ~/code $
Enter fullscreen mode Exit fullscreen mode
$ export PROMPT='[%*] %n@%m %~ $ '
[23:38] br@morenika ~/code $
Enter fullscreen mode Exit fullscreen mode
$ export PROMPT="[%* %n@%m %~]"$'\n'">>> "
[23:41 br@morenika ~/code/izk]
>>>
Enter fullscreen mode Exit fullscreen mode
$ export PROMPT="[%* %n@%m %1~]"$'\n'"%% "
[23:41 br@morenika izk]
%
Enter fullscreen mode Exit fullscreen mode

zsh goes even further by letting you define the content of a
right-sided prompt, through the RPROMPT environment variable, which
uses the same syntax as PROMPT.

Example

$ export PROMPT='%~ $ '; export RPROMPT='%*'
~/code $                                              21:04:00
Enter fullscreen mode Exit fullscreen mode

Note To make sure your changes are persisted, PROMPT and RPROMPT should
be exported in your .zshrc configuration file.

Adding Colors

Adding color is a good way to spice up your prompt as well as providing
some visual context. You can use color to indicate whether you are
running with super-user privileges, if the last command succeeded or
failed, or simply colorized each individual part of your prompt
(username, hostname, etc) in a different way to make it even simpler to
parse.

Adding color to your bash prompt

Bash allows you to style elements of your prompt by using 3-bit ANSI9
codes defining a zone associated with a potential effect, foreground
color and background color.

Each effect, background or foreground color has an associated code,
described in the following tables. The combination of these parameters
is called Select Graphic Rendition,
which is defined as a semicolon (;) separated list of codes.

Effect ANSI Code
Normal 0
Bold 1
Faint 2
Italic 3
Underline 4
Strike through 9
Background Color ANSI Code
Red 41
Green 42
Brown 43
Blue 44
Purple 45
Cyan 46
White 47
Bright black 100
Bright red 101
Bright green 102
Bright brown 103
Bright blue 104
Bright purple 105
Bright cyan 106
Bright white 107
Foreground Color ANSI Code
Black 30
Red 31
Green 32
Brown 33
Blue 34
Purple 35
Cyan 36
White 37
Bright black 90
Bright red 91
Bright green 92
Bright brown 93
Bright blue 94
Bright purple 95
Bright cyan 96
Bright white 97

Examples of SGRs

  • blue text: 34
  • bold green text: 1;32
  • purple text on a white background: 35;47
  • bold red text on a bright cyan background: 1;31;106
  • bold and striked-through brown text on a green background 1;9;33;42

To define colorized zones in your bash prompt, use the following
(granted, ugly) syntax:

\e[<SGR>mTEXT\e[m
Enter fullscreen mode Exit fullscreen mode

Examples

$ export PS1='[\t] \u@\h \W \e[32m$\e[m '
Enter fullscreen mode Exit fullscreen mode

The  raw `$` endraw  sign is now displayed in green
The $ sign is now displayed in green

$ export PS1='\e[31m\u\e[m@\e[32m\h\e[m \e[36m\W\e[m $ '
Enter fullscreen mode Exit fullscreen mode

The username is in red, the hostname in green and the path is in cyan.
The username is in red, the hostname in green and the path is in cyan.

Color palettes

Notice how an ANSI code only maps to a color name? That's because it is
up to your terminal to interpret and render that color name into an
actual color, meaning that the same prompt configuration could be
rendered differently on two different terminals.

Mapping ANSI color names to actual key="rgb">RGB colors is done through what is called color
palettes
.

Following are two different color schemes, as well as the associated
rendered prompt, both using the same PS1 value, used in the previous
example.

The popular Solarized Dark color scheme
The popular Solarized Dark color scheme

The Pastel (Dark Background) color scheme
The Pastel (Dark Background) color scheme

As you can see, these both look quite different from the prompt
displayed in the
previous screenshot
, even though the underlying prompt
configuration is exactly the same. This means that, even if using 16
colors can feel limiting, you actually can map these colors to any color
you like. The ANSI color system just prevents you from having more than
16 different colors in your prompt.

Note I recommend you to have a look at the
mbadolato/iTerm2-Color-Schemes10 project, showcasing popular color
palettes and providing you with the configuration files allowing you to
used them in many terminal applications (and not just iTerm2 contrary to
what its name suggests).

Up to 256 colors

As computers eventually started to have 256 colors graphics card, a 8
bit ANSI code scheme was introduced, allowing the user to render 256
colors in their terminal, instead of 16.

The 8-bit ANSI code syntax is \e[38;5;n where the colors associated
with each value of n between 0 and 255 are represented in the
following table11.

The 8-bit ANSI code allows you to render more than the initial 16 available colors
The 8-bit ANSI code allows you to render more than the initial 16 available colors

Examples

# Using 256-bit ANSI codes
$ TIME="[\e[38;5;33m\t\e[m]"  # blue
$ USERNAME="\e[38;5;200m\u\e[m"  # pink
$ HOSTNAME="\e[38;5;139m\h\e[m"  # purple
$ WORKDIR="\W"  # no color
$ DOLLAR="\e[38;5;41m$\e[m"  # green
$ export PS1="${TIME} ${USERNAME}@${HOSTNAME} ${PTH} ${DOLLAR} "
Enter fullscreen mode Exit fullscreen mode

These ANSI codes sure are awful to read but they make for pretty colors
These ANSI codes sure are awful to read but they make for pretty colors

Note Not all terminals support 256 colors, but most of the modern ones
should. To this day, GNOME Terminal, Konsole, Terminator, XFCE4
Terminal, iTerm2, Terminal (macOS) and tmux all support 256 colors.

Contrary to the 3-bit ANSI codes, the 8-bit codes are insensitive to
color schemes changes, as shown in the following examples, both re-using
the same PS1 configuration than in the key="fig:256col-prompt">previous screenshot.

The colors remain unchanged
The colors remain unchanged

Adding color to your zsh prompt

Everything we've explained in the previous section is still valid for
zsh: you can use 3 or 8 bit ANSI color codes just fine. However, zsh
also provides you with a much easier and readable color system:

  • each color can be represented as either black, red, green, yellow, blue, magenta, cyan or white, or a number between 0 and 255
  • %F{color}Text%f: changes the Text foreground color to color
  • %K{color}Text%k: changes the Text background color to color
  • %BText%b: displays Text in boldface
  • %UText%u: underlines Text

Example

The current working directory in blue and the dollar sign in bold pink
The current working directory in blue and the dollar sign in bold pink

Displaying dynamic data in the prompt

We can make our prompt display dynamic context to make it even more
informative. To do this, we can execute a function as part of our PS1
environment variable. The shell will call that function every time it
renders the prompt.

The idea is to be able to have as much information as possible in your
prompt at the ready, but only when necessary.

Displaying dynamic data in bash

Let's say that we want to colorize the $ of our prompt in green if the
last command was successful, and in red if it failed. We can wrap that
logic into the following colorized_prompt bash function, and have it
called every time PS1 is rendered by including $(colorized_prompt)
in the environment variable.

The $(colorized_prompt) syntax means "call the colorize_prompt function", and will be expanded into the output of the function (what it prints), which will contain ASCII color codes colorizing the prompt.

function colorized_prompt {
    if [[ $? ]]; then
        printf "\e[32m$\e[m"
    else
        printf "\e[31m$\e[m"
    fi

}
export PS1='[\t] \W $(colorized_prompt) '
Enter fullscreen mode Exit fullscreen mode

Note $? is a special bash parameter that expands to the exit status of the previously executed command. The norm is to have an exit status of 0 if the command executed successfully, and any other exit status indicates an error.

$ pwd
/home/br
$ echo $?
0
$ cmdnotfound
bash: cmdnotfound: command not found
echo $?
127
Enter fullscreen mode Exit fullscreen mode

The syntax if [[ $? ]]; then thus translates to “if the last command
executed successfully, then…”.

The prompt is green after a successful command and red after a failed one
The prompt is green after a successful command and red after a failed one

Displaying dynamic data in zsh

Dynamic data can be injected in your prompt the same way than in bash,
by executing functions at rendering time. zsh however provides you
with ternary conditionals, that is to say expressions that either
evaluate to one value or the other depending on a condition, to reach
the same goal. A ternary conditional has the following syntax

%(<condition>.<success value>.<failure value>)
Enter fullscreen mode Exit fullscreen mode

If the condition is true, then the expression is evaluated to the
success value. On the other hand, if the condition is false, the
expression will be evaluated to the failure value.

You can read a ternary conditional as if condition, then, else. It's
actually a common pattern called ternary expression you might
encounter in many programming languages.

Here is a list of useful built-in conditions provided by zsh.

Condition Meaning
n? True if the previous command exited with the exit status n
nd True if the day of the month is equal to n
nw True if the day of the week is equal to n (Sunday = 0).
! True if the shell is running with super-user privileges (as the root user)

Examples

$ export PROMPT='%F{%(0?.green.red)}$ %f'
Enter fullscreen mode Exit fullscreen mode

Displays a dollar prompt in green if the last command was successful, or red if it failed
Displays a dollar prompt in green if the last command was successful, or red if it failed

$ export PROMPT='%* %1~ %(!.#.$) '
Enter fullscreen mode Exit fullscreen mode

Display a dollar sign if you run your regular user, and a hash if you are running in super-user mode
Display a dollar sign if you run your regular user, and a hash if you are running in super-user mode

Note The full list of ternary conditionals is available in the zsh
documentation12.

Adding emoji to your prompt

Modern terminal support non-ASCII characters, such as emoji. Like
colors, they can be convenient to convey information in a very
space-efficient fashion.

For example, during the process of writing that book, I displayed the
associated total word count in my prompt to keep me motivated. That word
count would however only be displayed when I was located in the root
directory of the project, in the spirit of only displaying context when
necessary.

Shell configuration frameworks

Up until now, we have seen how to tailor your prompt by adding colors,
context, dynamic information computed on-the-fly. While you can
certainly spend hours customizing up to “perfection” (trust me, I have
been there…), you can also take another route and benefit from other
people's work, using a shell configuration key="framework">framework.

These frameworks provide you with a large choice of prompt themes,
helpers, options, additional command auto-completions, plug-ins, and are
regularly updated by a community of developers around the world.

To this day, the most famous zsh configuration frameworks are Oh My
Zsh13 and Prezto.14 While we can't fully attribute zsh's success
to them (Oh My Zsh was first released around 2010, 20 years after zsh's
first release), they certainly have helped in driving community adoption
in the last couple of years15.

Comparison of Google Trends associated with zsh and Oh My Zsh
Comparison of Google Trends associated with zsh and Oh My Zsh

We will introduce you to the concepts behind Oh My Zsh, but it will then
be up to you to explore, and select a theme as well as plug-ins you like
(or even not use them at all!). After all, it is your development
environment, and henceforth, your choice.

Note bash has a similar framework, inspired by Oh My Zsh, called
bash-it.16 We won't cover it in details but we encourage you to
look at it if don't feel like using zsh but still want to use a
configuration framework.

Oh My Zsh

Quoting the official website,

Oh My Zsh is a delightful, open source, community-driven framework for
managing your Zsh configuration. It comes bundled with thousands of
helpful functions, helpers, plug-ins, themes, and a few things that
make you shout…

To install it, run the following command in a shell, which will download
an installation script, and run it on your computer.

$ sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
Enter fullscreen mode Exit fullscreen mode

Once the script has finished running, you should see a message stating
that Oh My Zsh has been installed, and that plug-ins, themes and options
should be enabled by changing the configuration living under ~/.zshrc.

Before, we do, let's inspect our environment variables, to see how Oh My
Zsh configures itself.

$ printenv | grep ZSH
ZSH=/home/br/.oh-my-zsh
Enter fullscreen mode Exit fullscreen mode

That ZSH environment variable points to the Oh My Zsh installation
directory. The framework also injected a couple of other variables
defining specific configuration values.

$ set | grep ZSH
ZSH=/home/br/.oh-my-zsh
ZSH_ARGZERO=zsh
ZSH_CACHE_DIR=/home/br/.oh-my-zsh/cache
ZSH_COMPDUMP=/home/br/.zcompdump-morenika-5.7.1
ZSH_CUSTOM=/home/br/.oh-my-zsh/custom
ZSH_EVAL_CONTEXT=toplevel
ZSH_NAME=zsh
ZSH_PATCHLEVEL=zsh-5.7.1-0-g8b89d0d
ZSH_SPECTRUM_TEXT='Arma virumque cano Troiae qui primus ab oris'
ZSH_SUBSHELL=1
ZSH_THEME=robbyrussell
ZSH_VERSION=5.7.1
Enter fullscreen mode Exit fullscreen mode

Picking a theme

We can see that the default theme is robbyrussell (Robby Russell17
is the creator of Oh My Zsh). The full list of available themes is
available online18, along with screenshots.

You can also get the list by running the following command, as all
themes are defined in $ZSH/themes.

$ ls -1 $ZSH/themes | sed 's/.zsh-theme//'
3den
adben
af-magic
afowler
...
Enter fullscreen mode Exit fullscreen mode

I suggest you scroll through the themes wiki, or simply pick a theme at
random from the previous command output, edit your ~/.zshrc
configuration file by updating the value of the ZSH_THEME variable,
and run source ~/.zshrc to reload it. That will get you a whole new
shell theme!

Feel free to rinse and repeat until you find a theme that suits you. In
the case where no built-in theme finds grace in your eyes, you can also
explore the external theme wiki19. If you find an external theme you
like, download its associated .zsh-theme file, and place it under
$ZSH/themes, then edit ~/.zshrc, and update the ZSH_THEME
accordingly.

Note If you want to further personalize a theme using some of the techniques
we covered in that chapter, I'd advise you clone it and maintain a
separate version, as your tweaks might get overridden at the next theme
update.

Export the ZSH_CUSTOM environment variable to $ZSH/custom, then run
the following commands.

$ mkdir -p $ZSH/custom/themes
$ cp $ZSH/themes/$ZSH_THEME.zsh-theme $ZSH/custom/themes/$ZSH_THEME-custom.zsh-theme
Enter fullscreen mode Exit fullscreen mode

Then add ZSH_THEME=<old zsh theme>-custom to your ~/.zshrc.

Useful configuration options

Oh My Zsh has a couple of options you can enable or disable by editing
~/.zshrc. I suggest you take a look at them and choose what to
activate. Here are some personal recommendations.

Automatic command correction

zsh can suggest a command correction if it detects a mistyped command.
To enable the automatic command correction, add
ENABLE_AUTO_CORRECTION='true' to ~/.zshrc.

$ sl
zsh: correct 'sl' to 'ls' [nyae]? y
Android                bin   Desktop    Downloads  Firefox_wallpaper.png  Pictures
AndroidStudioProjects  code  Documents  Dropbox    Music                  Videos
Enter fullscreen mode Exit fullscreen mode

The 4 options are:

  • n (no): run the mistyped command
  • y (yes): run the suggested command
  • a (abort): stop and do nothing
  • e (edit): edit your command before re-running it

Note zsh's auto-correction feature can sometimes be over-zealous and is not
to everyone's liking20. If you end up repeatedly fighting it for a
given command (e.g. git status wrongly autocorrected to git stats),
you can define an alias for the command by prefixing it with
nocorrect.

alias git status='nocorrect git status'
Enter fullscreen mode Exit fullscreen mode
Automatic Oh My Zsh updates

To make sure you regularly get new plug-ins and bug fixes, Oh My Zsh can
automatically and regularly update itself. To do so, set the following
options in ~/.zshrc:

  • DISABLE_UPDATE_PROMPT=true: update Oh My Zsh without asking for confirmation
  • UPDATE_ZSH_DAYS=30: update Oh My Zsh every 30 days

Add plug-ins

Oh My Zsh comes with more than 250 plug-ins, each of them either
defining aliases or improved auto-completion for a given set of
commands. Refer to the Oh My Zsh wiki page21 to see the full list of
available plug-ins. To enable a given plug-in, add its name to the
plugins list in ~/.zshrc, then run source ~/.zshrc.

Example:

- plugins=(git)
+ plugins=(git python)
Enter fullscreen mode Exit fullscreen mode

If you regularly use a command listed in the plug-in wiki page, you
should probably try to enable the associated plug-in! I however suggest
enabling the following general-purpose plug-ins.

  • common-aliases22: Collection of useful aliases, not enabled by default since they may change some user defined aliases
  • colored-man-pages: colorize man pages

Colorized man pages are much easier to read!
Colorized man pages are much easier to read!

  • extract: define an extract alias that can extract any type of archive (.zip, .tar.gz, .bzip, etc)23

The following plug-ins are not provided by default, I find them so
useful that I suggest you install them and give them a try.

  • zsh-autosuggestions24: emulate the fish autosuggestion by suggesting commands as you type them, saving you from using Ctrl - R to look into your shell history. Any suggestion can be accepted by hitting or ignored by just continuing typing.

I just typed  raw `ls` endraw  and I immediately get a completion suggestion
I just typed ls and I immediately get a completion suggestion

Suggestion accepted!
Suggestion accepted!

  • zsh-syntax-highlighting25: provide syntax highlighting within the zsh command line. It also colorizes the name of the command you type in green if it is found, and in red if not.

 raw `ls` endraw  is a valid command
ls is a valid command

 raw `cmdnotfound` endraw  is not
cmdnotfound is not

Uninstalling Oh My Zsh

If you find that Oh My Zsh isn't for you, you can uninstall it by
running the uninstall_oh_my_zsh function. Your previous configuration
will be restored.

Summary

I strongly believe that learning how to configure and personalize your
own shell is an important part of becoming a developer. I'd even go as
far as calling it a ritual. On a personal level, it helped me overcome
the almost mystic reputation of the terminal by making it my own.

Configuring your shell might never really be fully completed. Do you
find yourself executing a long command repeatedly? Make it an alias. If
an alias does not cut it, or if it should take arguments, write a shell
function instead. Are you oftentimes wondering on which branch, project
or profile you are currently running? Add it to your prompt. If your
prompt starts to feel a little crowded, you might be able to condense it
by using colors and emoji.

Making your own tools and customizing your shell is an investment, but
it is also an inherent part of being a software developer, which will
allow you to do more, faster, and will help you feel more at home in
your shell. It's also quite a bit of fun!

Going further

4.1: Look into your terminal's preferences and try to change the
color scheme, or remap ANSI colors to different RGB colors.

4.2: Try different fonts, such as Source Code Pro,
Fira Code Pro, Inconsolata or Jetbrains Mono and pick the one you
like most

4.3: Explore your terminal preferences, and experiment with
different settings.

4.4: Try to change the colors of the different sections of your
prompt

Essential Tools and Practices for the Aspiring Software Developer is a self-published book project by Balthazar Rouberol and Etienne Brodu, ex-roommates, friends and colleagues, aiming at empowering the up and coming generation of developers. We currently are hard at work on it!

The book will help you set up a productive development environment and get acquainted with tools and practices that, along with your programming languages of choice, will go a long way in helping you grow as a software developer. It will cover subjects such as mastering the terminal, configuring and getting productive in a shell, the basics of code versioning with git, SQL basics, tools such as Make, jq and regular expressions, networking basics as well as software engineering and collaboration best practices.

If you are interested in the project, we invite you to join the mailing list!


  1. https://gnometerminator.blogspot.com/p/introduction.html 

  2. https://iterm2.com/ 

  3. https://github.com/tonsky/FiraCode 

  4. https://www.jetbrains.com/lp/mono/ 

  5. https://www.theverge.com/2019/6/4/18651872/apple-macos-catalina-zsh-bash-shell-replacement-features 

  6. https://fishshell.com 

  7. http://ezprompt.net 

  8. http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html 

  9. https://en.wikipedia.org/wiki/ANSI_escape_code 

  10. https://github.com/mbadolato/iTerm2-Color-Schemes 

  11. Source: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors 

  12. http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html#Conditional-Substrings-in-Prompts 

  13. https://ohmyz.sh 

  14. https://github.com/sorin-ionescu/prezto 

  15. Source:
    https://trends.google.com/trends/explore?date=all&q=oh%20my%20zsh,%2Fm%2F0nrgk 

  16. https://github.com/Bash-it/bash-it 

  17. https://github.com/robbyrussell 

  18. https://github.com/ohmyzsh/ohmyzsh/wiki/Themes 

  19. https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes 

  20. https://github.com/ohmyzsh/ohmyzsh/issues/534 

  21. https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins 

  22. https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins#common-aliases 

  23. https://www.xkcd.com/1168/ 

  24. https://github.com/zsh-users/zsh-autosuggestions/blob/master/INSTALL.md 

  25. https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/INSTALL.md 

Top comments (3)

Collapse
 
fanchgadjo profile image
Francois K

Great and useful article ! 🎉 I use most of those tools after getting tired of writing 'git status' all day long. What do you think about Powerlevel10k ?

Collapse
 
brouberol profile image
Balthazar Rouberol

I have tested it briefly and it looks immensely powerful! I haven't made the jump but it felt fast, featureful and extensible.

Collapse
 
fanchgadjo profile image
Francois K

Configuration is easy, loading is fast even with loads of zsh plugins.