Khang Nguyen

Making zsh feel like home


The thing that greets you when you open the terminal is the shell.

% █

macOS used to ship with bash as the default shell, until in WWDC 2019 it was announced that zsh will replace it as the default shell.

The following snippets can either be placed inside ~/.zshrc or be ran directly in the z shell as commands. If you edit ~/.zshrc, for changes to take effect you need to either exit and reopen the terminal, or run the command source ~/.zshrc.

Aliases

For things you find yourself typing all the time.

alias zr="source ~/.zshrc"

After running this command, you can now type zr and press enter and zsh would interpret that as if you typed source ~/.zshrc and pressed enter.

Aliases can also save you a lot more keystrokes:

alias ls="ls -a --group-directories-first --color=always"
alias ll="ls -al --group-directories-first --color=always"

Functions

Sometimes the one-liner nature of alias isn’t enough. Or sometimes you want to add things after the command (arguments). Functions are perfect for this.

First of all, functions can be used just like aliases, so the alias of zr is equivalent to this function:

function zr() {
  source ~/.zshrc
}

To pass an argument into a function, do this:

function p() {
  echo $1
}

The number denotes the order of the argument given. $1 will refer to the first argument, $2 will refer to the second, and so on.

So if you were to run the command p helloworld, zsh will print out helloworld, as if you typed in echo helloworld.

With functions you can also bring in logic like if-else statements, for example:

function gcm() {
  if [ "$1" ]; then
    git commit -m $1
  else
    git commit
  fi
}

Environment variables

Variables are called by pre-pending the $ symbol.

FOO="bar"
echo $F00

Running the two commands above, you would have assigned "bar" to the variable FOO, and the terminal will print bar.

Some environment variables are defined by default. One such example is $HOME.

echo $HOME

will print the current user’s home directory. For example, mine prints /home/khang.

Personally, I use these variables to store key locations on my computer, such as my main working directory and my configuration directories

REPOS="$HOME/repos"
ZSH_DOTS="$REPOS/zsh"

Splitting up your zshrc

Now this is the highlight of the article. When writing all these into one file, namely ~/.zshrc, things can get messy, and so it’s often better to split it up into multiple files.

I do it by putting this into my ~/.zshrc:

ZSH_DOTS="$HOME/repos/zsh"
sourceDirs=()
[ `uname` = "Linux" ] && sourceDirs+=(linux)
[ `uname` = "Darwin" ] && sourceDirs+=(mac)
sourceDirs+=(core brew)

for d in $sourceDirs[@]; do
  fs=($(find $ZSH_DOTS/$d -type f))
  for f in $fs[@]; do
    source "$f";
  done
done

What this does is it finds all the files under the following directories

~/repos/zsh/brew
~/repos/zsh/core
~/repos/zsh/linux # (only if on Linux)
~/repos/zsh/mac   # (only if on macOS)

And sources all of them as though they were part of ~/.zshrc.

This has helped be organize my zsh configurations so much better. Probably the best thing I’ve done in zsh in 2021.