This is a short set of notes regarding zsh on macOS and Ubuntu, motivated by the upcoming switch to zsh as the default shell in macOS Catalina.


First off, you don’t need to install it from brew. macOS Mojave comes with a perfectly serviceable zsh 5.3 in /bin/zsh, but by all means feel free to use whatever version you want.

In Ubuntu 18.04 (and WSL), sudo apt-get install zsh installs it for you, and on any system you can change your default shell in the usual way using chsh (man chsh for details and examples, don’t go blindly copying stuff from blog posts…).

The Zero Frill Approach

Almost every zsh post I came across mentions oh-my-zsh or prezto and themeing and a bunch of pretty, colorful, but non-critical things it sets up for you.

I will have none of that, thank you.

Being a purist/stoic, I want to understand what the single most important piece of code I run inside a terminal does, and want its setup to be as minimal (and cross-platform) as possible. I’ve long kept shared versions . bashrc in either Dropbox or OneDrive, and am doing the same for .zshrc now as well.

Command Line Editing

Even though I´m a vim user, I am used to having emacs bindings for line editing:

bindkey -e

Prompt Setup

I like my PS1 to be short, concise and, above all consistent everywhere:

I’m willing to concede on the $ (since zsh uses % for standard users and # for root), but I like minimal color, and appreciate that zsh can do it without cluttering PS1 with ANSI escape codes:

autoload -Uz colors && colors

# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
    xterm-color|*-256color) color_prompt=yes;;

if [ "$color_prompt" = yes ]; then
    PS1="%{$fg_bold[green]%}%[email protected]%m%{%f%}:%{$fg_bold[blue]%}%~%{$reset_color%}%# "
    PS1="%[email protected]%m:%~%# "
unset color_prompt

Terminal Titles

The prompt is nice when you’re looking at the terminal, but useless when you’re sorting through a bunch of terminal windows. So I always set the terminal title as well:

# If this is an xterm set the title to [email protected]:dir
case $TERM in
    precmd () {print -Pn "\e]0;%[email protected]%m:%~%#\a"}

Command Completion

When you need to use bash autocompletion configurations, all you need to do is:

autoload -U +X bashcompinit && bashcompinit

Azure CLI

For instance, for the specific case of az, assuming you’re using pyenv and got argcomplete installed like me, this is what you need to do:

# run this once
activate-global-python-argcomplete --user

# add this to .zshrc
source $HOME/.bash_completion.d/python-argcomplete.sh
eval "$(register-python-argcomplete az)"

SSH Keychain

Another essential I keep near the end of my .zshrc in Ubuntu:

eval `keychain --agents ssh --eval id_rsa --quiet -Q`

Python and NPM

My current settings for pyenv and npm “global” module installations:

export PYENV_ROOT=$HOME/.pyenv
eval "$(pyenv init -)"
export GOPATH=$HOME/Library/Go

export MANPATH="$NPM_PACKAGES/share/man:$(manpath)"