Replacing Bash with ZSH on OSX

Danny Smith
rootpath
Published in
5 min readFeb 26, 2015

--

About a year ago I bought a new MacBook, and while setting it up, I used parts of Thoughtbot’s laptop setup scripts. Ever since then, I’ve been meaning to switch my shell from bash to zsh. There are a whole bunch of benefits.

iTerm 2 instead of Terminal

While I’m switching shell, I thought it might be an idea to switch my terminal app too. Although I’ve got no real problems with Terminal.app, iTerm 2 offers a few advantages, the main one being the HotKey window that allows me to open a terminal anywhere with a key combination (in my case Shift + Space):

iTerm 2 Hotkey Window

Having set this up in term’s preferences, we can set iTerm to open at login and hide the iTerm dock icon with:

/usr/libexec/PlistBuddy -c ‘Add :LSUIElement bool true’ /Applications/iTerm.app/Contents/Info.plist

Setting up ZSH

Having dug about on the internet for articles covering zsh, it seems the best way of customizing it is through oh-my-zsh. Because I’d like to customize my theme, I made a fork to work with.

The first thing to do is install zsh using homebrew and clone oh-my-zsh into our home directory:

cd ~ brew install zsh git clone https://github.com/dannysmith/oh-my-zsh .oh-my-zsh

We now need to edit /etc/shells and replace the current zsh line with the location of the one installed by homebrew (which should be /usr/local/bin/zsh).

We’ll deal with setting up the .zshrc file in a minute, which is where we’ll look at how to include oh-my-zsh. Before we do, we need to set up a new prompt.

Custom Prompt

Everyone has their own preference when it comes to their prompt, and oh-my-zsh offers a huge selection. Personally, I like mine to include the current directory and, if we’re in a git repo, the current branch and status. If it’s clean, we’ll show a green star, if it’s dirty we’ll show a red one:

Shell Prompt

We can achieve this by adding a new zsh-theme file to our ~/.oh-my-zsh/themes directory:

ZSH_THEME_GIT_PROMPT_SUFFIX=”$reset_color”ZSH_THEME_GIT_PROMPT_DIRTY=”$fg[red]⋆” # Show if git is dirtyZSH_THEME_GIT_PROMPT_CLEAN=”$fg[green]⋆” # Show if git is cleanpurple=”%F{135}”# Create a git prompt showing the current branchfunction git_prompt_info() {ref=$(git symbolic-ref HEAD 2> /dev/null) || returnecho “ $purple- $(parse_git_dirty)$fg[yellow]$(current_branch)”}# Create the promptPROMPT=’$fg[cyan]%~$(git_prompt_info)$fg[green]→$reset_color ‘# If we’re logged in as root, prefix the arrow with the word ROOTif [[ “$USER” == “root” ]]; thenPROMPT=’$fg[cyan]%~$(git_prompt_info)$fg[red]ROOT$fg[green]→$reset_color ‘fi

.zshrc

Much of my .zshrc file was move directly from my .bash_profile. Let’s walk through the file:

First, we set the ZSH variable to point to the loaction of our oh-my-zsh installation, and set the ZSH theme to use. I called my theme dannysmith.zsh-theme.

# Path to your oh-my-zsh installation.
export ZSH=$HOME/.oh-my-zsh
ZSH_THEME=”dannysmith”

Now we can tell oh-my-zsh to load the plugins we want. Be aware that each of thses will slow down the time it takes to load a new shell, so stick to the ones you actually use. We can also set up a couple of utility environment variables and include our PATH.

plugins=(bower brew brew-cask bundler cloudapp coffee colored-man colorize common-aliases cp docker gem git git-extras gitignore heroku history osx rails rake rbenv ruby zsh-syntax-highlighting)

# User configurationsource $ZSH/oh-my-zsh.sh# Compilation flagsexport ARCHFLAGS=”-arch x86_64"# sshexport SSH_KEY_PATH=”~/.ssh/dsa_id”# Code Completion from zsh-completionsfpath=(/usr/local/share/zsh-completions $fpath)export PATH=”/Users/danny/.rbenv/shims:/usr/local/mysql/bin:/usr/local/bin:/usr/local/share/npm/bin:/usr/local/lib/node_modules:/usr/local/git/bin:/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin”# For Travis Gem[ -f /Users/danny/.travis/travis.sh ] && source /Users/danny/.travis/travis.sh

Next, we can set Sublime Text as our default editor and create some aliases for common commands. I’ve got a lot of aliases for git, since I use it so frequently.

# NOTE: Sublime text is aliased as “st”, through a symlink in /usr/bin.#Sets SVN, GVS and default editors to Sublime Text 2export EDITOR=”st -w”export CVSEDITOR=”st -w”export SVN_EDITOR=”st -w”# common typosalias ts=’st’alias st.=’st .’#Alias for wgetalias wget=”curl -O”# Start SQLalias smysql=”/usr/local/bin/mysql.server start”# # Enable shims and autocompletion for rbenvif which rbenv > /dev/null; then eval “$(rbenv init -)”; fi# More Git aliasesalias git=’hub’alias g=’git’alias gst=’git status -s’alias gpull=’git pull’alias gp=’git push’alias gf=’git fetch’alias gd=’git difftool’alias gc=’git commit -v’alias gca=’git commit -v -a’alias gcm=’git commit -m’alias gco=’git checkout’alias gb=’git branch’alias gba=’git branch -a’alias glog=’git log —oneline —decorate’alias glogg=’git log —oneline —decorate —graph’alias glogs=’git log —oneline —decorate —stat’alias gcl=’git clone’alias gdc=’git difftool —cached’# #Aliases for lsalias ll=’ls -lh’alias l=’ls -lhA’alias lsa=’ls -a’alias rm=’rm -i’#Apache commandsalias apaches=’sudo apachectl start’alias apacher=’sudo apachectl restart’alias apachestop=’sudo apachectl stop’# Get OS X Software Updates, and update installed Ruby gems, Homebrew, npm, and their installed packagesalias update=’sudo softwareupdate -i -a; brew update; brew upgrade; brew cleanup; npm update npm -g; npm update -g; sudo gem update —system; sudo gem update’# IP addressesalias ip=”dig +short myip.opendns.com @resolver1.opendns.com”alias localip=”ipconfig getifaddr en1"alias ips=”ifconfig -a | grep -o ‘inet6\? \(addr:\)\?\s\?\(\(\([0–9]\+\.\)\{3\}[0–9]\+\)\|[a-fA-F0–9:]\+\)’ | awk ‘{ sub(/inet6? (addr☺? ?/, \”\”); print }’”# Enhanced WHOIS lookupsalias whois=”whois -h whois-servers.net”# Flush Directory Service cachealias flush=”dscacheutil -flushcache && killall -HUP mDNSResponder”# Clean up LaunchServices to remove duplicates in the “Open With” menualias lscleanup=”/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user && killall Finder”# View HTTP trafficalias sniff=”sudo ngrep -d ‘en1' -t ‘^(GET|POST) ‘ ‘tcp and port 80'”alias httpdump=”sudo tcpdump -i en1 -n -s 0 -w — | grep -a -o -E \”Host\: .*|GET \/.*\””# Reload the shell (i.e. invoke as a login shell)alias reload=”exec $SHELL -l”# Faster npm for europeanscommand -v npm > /dev/null && alias npme=”npm —registry http://registry.npmjs.eu"# Kill all the tabs in Chrome to free up memory# [C] explained: http://www.commandlinefu.com/commands/view/402/exclude-grep-from-your-grepped-output-of-ps-alias-included-in-descriptionalias chromekill=”ps ux | grep ‘[C]hrome Helper —type=renderer’ | grep -v extension-process | tr -s ‘ ‘ | cut -d ‘ ‘ -f2 | xargs kill”# Shortcutsalias dl=”cd ~/Downloads”alias dt=”cd ~/Desktop”alias dev=”cd ~/Dropbox/dev”alias inbox=”cd ~/Dropbox/Inbox”alias docs=”cd ~/Dropbox/Documents”alias docsl=”cd ~/Documents”alias raf=”cd ~/RAF”alias sparta=”cd ~/Dropbox/Documents/Sparta”alias sshsparta=”ssh -X danny@unix.spartaglobal.com -R 52698:localhost:52698"

Enabling zsh as the default shell

Finally, we can change the default login shell to zsh:

chsh -s /usr/local/bin/zsh

Originally published at danny.is on December 26, 2014.

--

--

Danny Smith
rootpath

Helping companies become high-performance remote organisations. Currently working with @HeyOyster . Used to write code. Occasional blues musician.