Advanced Zsh: Aliases and Functions Techniques
What Are Aliases and Functions in Zsh?
Aliases and functions are two powerful mechanisms in Zsh that allow you to create shortcuts, automate repetitive tasks, and build complex command‑line workflows. An alias is a simple name substitution: when you type the alias, Zsh replaces it with the defined string. Functions, on the other hand, are full‑fledged shell scripts that can accept arguments, use control structures, and encapsulate logic. Together they form the backbone of a highly personalised and efficient terminal experience.
Why They Matter for Developer Productivity
Every keystroke you save adds up over a day’s work. Aliases reduce typing for long or frequently used commands (e.g., g for git, dc for docker compose). Functions allow you to create multi‑step operations, handle edge cases, and reuse logic across different contexts. Mastering these techniques helps you:
- Execute complex pipelines with a single command
- Maintain a consistent environment across machines
- Reduce errors by codifying best practices
- Customise your shell to match your workflow
Setting Up Your Zsh Environment
All aliases and functions are typically defined in your ~/.zshrc file. After adding definitions, run source ~/.zshrc or open a new terminal. For large collections, consider splitting definitions into separate files and sourcing them:
# In ~/.zshrc
source ~/.zsh/aliases.zsh
source ~/.zsh/functions.zsh
fpath+=~/.zsh/functions
autoload -Uz ~/.zsh/functions/*(:t)
This keeps your main config clean and maintainable.
Basic Aliases vs. Functions
The simplest alias looks like this:
alias ll='ls -lh'
When you type ll, Zsh expands it to ls -lh. Aliases cannot accept arguments directly—they are pure text replacements. For example:
alias g='git'
# g status becomes git status – works because the alias is replaced before parsing
A function can do the same but also handle arguments:
g() {
git "$@"
}
The "$@" passes all arguments to git. Functions give you the flexibility to add logic, default values, and error handling.
Advanced Alias Techniques
Global Aliases (alias -g)
Global aliases are replaced anywhere on the command line, not just at the start. This is incredibly useful for creating pipeline shortcuts:
alias -g G='| grep'
alias -g L='| less'
alias -g T='| tail -20'
# Usage: cat log.txt G error L
Now cat log.txt G error L becomes cat log.txt | grep error | less. Use global aliases sparingly because they can interfere with command names.
Suffix Aliases (alias -s)
Suffix aliases allow you to open a file by typing its name and pressing Enter, as long as the file has a known extension:
alias -s {txt,md}=nvim
alias -s {jpg,png}=feh
alias -s pdf=zathura
# Now just type "notes.md" and it opens in neovim
This mimics the behaviour of macOS’s open but is fully customisable.
Aliases with Arguments (the function workaround)
Because pure aliases cannot handle arguments, a common pattern is to define a short alias that calls a function:
alias docker-ps='docker_ps_func'
docker_ps_func() {
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"
}
This keeps the alias short while allowing complex logic in the function.
Advanced Function Techniques
Named Arguments and Defaults
Zsh functions can use positional parameters ($1, $2, …) and assign defaults with ${1:-default}:
mkcd() {
local dir="${1:-.}" # default to current directory
mkdir -p "$dir" && cd "$dir"
}
# Usage: mkcd /tmp/newproject
For more readability, use the local keyword and named variables:
backup() {
local src="$1"
local dest="${2:-/backup}"
if [[ -z "$src" ]]; then
echo "Usage: backup <source> [destination]"
return 1
fi
rsync -avh "$src" "$dest"
}
Functions with Options (getopts)
To handle flags like -v or --verbose, use the built‑in getopts or the newer zparseopts module. Example using zparseopts:
# Requires: zmodload zsh/zutil
search() {
local verbose=0 pattern=""
zparseopts -D -E -A opts v=verbose -verbose=verbose
pattern="${1:?Error: pattern required}"
if [[ -n "$verbose" ]]; then
echo "Searching for: $pattern"
fi
grep -r "$pattern" .
}
Now search -v "TODO" prints an extra message before searching.
Functions for Complex Pipelines
Encapsulate multi‑step operations. For instance, a function to find the largest files in a directory:
bigfiles() {
local count="${1:-10}"
local dir="${2:-.}"
du -ah "$dir" | sort -rh | head -n "$count"
}
# Usage: bigfiles 5 /var/log
You can chain functions with pipes or use them inside other functions:
git-prune-branches() {
git branch --merged | grep -v "\*\|main\|master" | xargs -r git branch -d
}
Autoloading Functions
For large custom libraries, place each function in its own file and use autoloading. Zsh will load the function only when it is first called, saving startup time.