I’ve recently been asked to share my shell setup, which if you ask me, that’s one of the highest levels of praise you can achieve as a software developer 🤣 In this article, I’ll describe the setup I’ve been using for the past few years, and how to achieve similar results yourself.
🖼️ The result
First, let’s look at what we’ll try to achieve by looking at a screenshot I took last year when showing off to a senior co-worker of mine. Visually speaking, almost nothing changed since then, so let me just be lazy for a while and re-use this overly annotated screenshot.
I think some people go for very minimalist shell setups, and I suppose you could say that I prefer the exact opposite of minimalist in this regard 😅 The screenshot above is missing two significant elements, which would be the exit code of previously executed command and presence of background processes - not to worry, these elements are not omitted, just hidden in case no interesting information is available to show (last process terminated successfully/no background processes are running respectively).
To achieve similar results, I believe you’ll need two pieces of puzzle that I’ll not cover in detail in this article:
- Capable terminal emulator (macOS’
Terminal.appdoesn’t qualify) – I’ve been living in the iTerm2 land since I migrated to macOS, always configured the superior Solarized Dark color theme;
- Nerd-patched font for all the special glyphs that our shell will show us – either patch a font of your liking yourself or go with one of the pre-patched fonts; popular choices include FiraCode, Hack, Inconsolata, Iosevka and others.
🐟🐚 It all starts in the shell…
bash for many years and
zsh for many more years, I switched to
fish shell a few years ago. While
zsh is a fine shell, I felt that
fish can be more user-friendly and easier to customize – but I recognize that this doesn’t come without drawbacks, namely that
fish shell doesn’t respect the traditional POSIX syntax so you’ll have to definitely alter some of your habits. Let’s first install
fish shell and then I’ll share a few tricks to get more familiar with
brew install fish echo /usr/local/bin/fish | sudo tee -a /etc/shells chsh -s /usr/local/bin/fish $(whoami)
Say “bye-bye” to
zsh because the next time you open a terminal, you should be welcomed by a friendly interactive shell, like so:
Next, install Oh My Fish, which is essentially a package manager for Fish shell, along with some essential plugins and themes:
curl -L https://get.oh-my.fish | fish omf install bobthefish # Theme omf install aws # AWS integration & command completion omf install bass # Allows running heavily Bash-dependant utilities, like nvm omf install brew # Integrate Homebrew paths omf install colored-man-pages omf install export # Bring back Bash-like export command omf install https://github.com/jhillyerd/plugin-git omf install osx # Finder/macOS integration and utilities omf install wifi-password omf install z # Autojump implementation
For more information about what these do, check the package list – for example,
wifi-password shows you the current WiFi password – not something you need every day, but when you need it, it’s very nice to have;
z allows you to quickly jump across often visited directories just by typing part of their names; and the
git plugin (documentation available here) gives you more
git aliases and abbreviations than you could ever remember.
You’ll notice that even with the
bobthefish theme installed and automatically activated, your shell prompt still looks way different from the first screenshot I presented – so let’s configure the shell and prompt. Listed below is the content of the
~/.config/fish/config.fish file I currently use, but feel free to adjust it to your heart’s content:
set -gx COLORTERM truecolor set -gx EDITOR nvim set -gx LANG cs_CZ.UTF-8 # Adjust this to your language! set -gx LC_ALL cs_CZ.UTF-8 # Adjust this to your locale! set -gx VIRTUAL_ENV_DISABLE_PROMPT true set -gx GOPATH $HOME/go set -x PATH $GOPATH/bin $HOME/.composer/vendor/bin $HOME/Library/Python/3.7/bin $PATH set -gx HOMEBREW_AUTO_UPDATE_SECS 86400 set -gx DOCKER_BUILDKIT 1 set -gx COMPOSE_DOCKER_CLI_BUILD 1 set -g fish_key_bindings fish_vi_key_bindings set -g fish_bind_mode insert # Title options set -g theme_title_display_process yes set -g theme_title_display_path yes set -g theme_title_display_user yes set -g theme_title_use_abbreviated_path yes # Prompt options set -g theme_display_ruby yes set -g theme_display_virtualenv yes set -g theme_display_vagrant no set -g theme_display_vi yes set -g theme_display_k8s_context no # yes set -g theme_display_user yes set -g theme_display_hostname yes set -g theme_show_exit_status yes set -g theme_git_worktree_support no set -g theme_display_git yes set -g theme_display_git_dirty yes set -g theme_display_git_untracked yes set -g theme_display_git_ahead_verbose yes set -g theme_display_git_dirty_verbose yes set -g theme_display_git_master_branch yes set -g theme_display_date yes set -g theme_display_cmd_duration yes set -g theme_powerline_fonts yes set -g theme_nerd_fonts yes set -g theme_color_scheme solarized-dark bind -M insert \cg forget if which asdf > /dev/null; status --is-interactive; and source (brew --prefix asdf)/asdf.fish; end if which direnv > /dev/null; direnv hook fish | source; end if which goenv > /dev/null; status --is-interactive; and source (goenv init -|psub); end if which rbenv > /dev/null; status --is-interactive; and source (rbenv init -|psub); end if which swiftenv > /dev/null; status --is-interactive; and source (swiftenv init -|psub); end
Line 42 binds a
forget function to the key combination of
Ctrl-G, so let’s create the
forget function right now by pasting the following into
function forget set -l cmd (commandline | string collect) printf "\nDo you want to forget '%s'? [Y/n]\n" $cmd switch (read | tr A-Z a-z) case n no commandline -f repaint return case y yes '' history delete --exact --case-sensitive -- $cmd commandline "" commandline -f repaint end end
What this does is allows you to easily remove command from shell’s history, for example if you typed sensitive information or made a typo in a command that you don’t want to get reminded of in the future. Activate it by going up the history with the up arrow key ⬆️⌨️ until you hit the command you wish to forget, then activate the function by pressing
Ctrl-G. Speaking of
fish functions, here’s one more you might find useful – get a random Git-related tip as spoken with a random pony anytime you open a new shell! First, let’s install the dependencies:
brew install ponysay npm install -g git-tip
Then put the following text into
function fish_greeting git-tip | ponysay end
If you followed the guide properly (and if I haven’t missed anything), your terminal should now look fairly similar to mine!
🦺 Fish survival guide
As I mentioned at the beginning of the article, Fish is often different. I hope that this little table will help you overcome the most problems you could face:
||You can keep using
||Type search term, then press ⬆️ key||Or omit search term for linear history browsing|
For more in-depth survival guide, be sure to check the official documentation.
And since this article is getting quite long, let’s save the Tmux part for next time!