← Back to DevBytes

Advanced Zsh: Aliases and Functions Techniques

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:

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.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles