1UP your Zsh abilities by autoloading your own functions
Tags: bash, tutorial, beginners
Published: 2020-05-24 12:15:59

Zsh is quickly becoming the shell of choice for software developers and, if you want to maximise your productivity at the CLI, you should know how to create and autoload your own Zsh functions.

![Photo by [Markus Spiske](https://unsplash.com/@markusspiske?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/11520/0*McipBU_CqmKDJf7V)

Even novice CLI users will have added the occasional *alias* in order to avoid repeatedly typing out a verbose command. Whilst aliases are great, they aren’t well suited to the more complicated, logical code snippets that you may want to run on a regular basis.

In this whistle-stop tour, I’ll show you how to create basic Zsh functions and integrate them with Zsh’s autoloading system so they’re available during interactive shell sessions.

### Creating our function

After reading this article, I’m sure you’ll be inspired to write lots and lots of functions but, before you get carried away, it’s good practice to create a directory to store them all. I usually create a hidden subdirectory in my home directory called *.zshfn*

By convention, each function is stored in a file with the same name; for the purposes of keeping this guide snappy, I’m going to create a very simple *clock* function that just displays the current time and so I’ll create a file called *clock* (no file extension) to put my function code in.
```shell
mkdir ~/.zshfn
touch $_/clock
```
Now edit the *clock* file and add the following snippet:
```shell
# Initialisation Code
echo "Initialising Clock"

# Display simple clock every second
clock () {
  while [ true ]
  do
    echo "=========="
    date +"%r";
    echo "=========="
    sleep 1;
    clear;
  done
}

# Clear the three lines from the terminal
clear() {
  for i in {1..3};
  do
      tput cuu1
      tput el
  done
}

clock
```
We’ll come back to the function later — for now just save the *clock* file.

### Configuring our *.zshrc* file

In order to make our function accessible whenever we startup a new terminal, we need to make a couple of modifications to the *.zshrc* file.

First we need to ensure we add our *.zshfn* function directory to the Zsh *file search path* (a.k.a *fpath*) so that Zsh knows it should look in our new directory for functions. As you might expect, the *fpath* is traversed from left-to-right like other unix path variables.

Secondly, we need to tell Zsh about the *clock* function we just created — this is achieved via the *autoload* command. The *autoload* command essentially instructs Zsh to register a function (called *clock*) using the contents of the *clock* file that is located in a directory somewhere along the *fpath*.
```shell
# Bottom of .zshrc file
fpath=( ~/.zshfn "${fpath[@]}" )
autoload -Uz clock
```
As you add more functions, you’ll find it becomes cumbersome to append each one to the end of the autoload command and so (if you want to be super cool) you can choose to autoload all files in your *.zshfn* folder using the following alternative:
```shell
# Bottom of .zshrc file
fpath=( ~/.zshfn "${fpath[@]}" )
autoload -Uz $fpath[1]/*(.:t)
```
If you’re wondering what the *-Uz* options do, they simply ensure that autoloading will do the right thing regardless of what other options you may have configured (i.e. enforces disabled alias-expansion and zsh style autoloading).

### Running our function

After saving our *clock* function and the *.zshrc* file we are now ready to test the function out. In your terminal begin typing *clock* — you should be able to tab-complete the function and if you have syntax highlighting turned on you should see that kick in too.

![Running like clockwork](https://cdn-images-1.medium.com/max/2272/1*VZAZMtDZzEaZjgRDm7Swng.png)

Hit return and you should see the following output:

![Running the clock file for the first time](https://cdn-images-1.medium.com/max/2272/1*MpYbbPFyYUFZFgm790DG0Q.png)

Remember that as far as Zsh is concerned, before running the *clock* function, the **entire contents of the *clock* file are used as the function definition**. This is why the first time you run *clock*, you see the initialisation code being executed.

Kill the function (*Ctrl-c*) and run the function again — you should see the following output the second time around:

![Second execution uses redefined function](https://cdn-images-1.medium.com/max/2272/1*qYxaqvwXgHRJDpH8fhx-9Q.png)

Notice that in the second execution, **the initialisation code does not run**— this is because the first time we ran the function, the *clock* function was redefined to use the actual *clock()* function defined in our file. This can be a really nice pattern to use if you have some sort of one-off initialisation you need to accomplish.

At this point you might be wondering why the *clock()* method is even needed? Well actually, it isn’t. You could replace the *clock* file with the following contents and it would work just fine.
```shell
echo "Initialising Clock"

while [ true ]
do
  echo "=========="
  date +"%r";
  echo "=========="
  sleep 1;
  for i in {1..3};
  do
      tput cuu1
      tput el
  done
done
```
If you now execute this version of the *clock* function twice in a row you’ll see that, because the *clock* function is not redefined, the initialisation code runs both times.

![Repeated executions all run the initialisation code](https://cdn-images-1.medium.com/max/2272/1*lzEwDshZwcY-RH0rO9cEhw.png)

Which approach you use is largely down to your use-case and stylistic preferences. I tend to prefer the first option (i.e. encapsulate my *clock* code in a *clock()* function block) but in many cases it is completely superfluous.

I hope you learned something from this quick write-up — there is a lot more to Zsh functions than covered here and if you want more detailed information, I’d recommend you check out [this resource](http://zsh.sourceforge.net/Doc/Release/Functions.html).

In any case, functions are a great way to optimise your CLI experience and it’s certainly worthwhile knowing how to use them 😎👍