Skip to main content
Latest post

My Z shell setup

I've been a Fish shell user for years. It was my shell of choice on my Linux systems until I purchased my MacBook Pro, when I switched to Z shell.

As a fairly new Z shell user, I thought it might be good for me to document how I install and configure it, so that I can replicate my setup on new servers etc.

Install

I run Debian on my servers, so adjust this command if you use a different Linux distro. I've included git and curl as Git is required to clone the Z shell scripts and curl is referenced in my .zshrc file.

sudo apt update
sudo apt install zsh git curl

Clone zsh scripts from GitHub

Run the following commands to create a directory to hold the zsh scripts before cloning them from GitHub:

mkdir -p ~/.zsh
git clone https://github.com/sindresorhus/pure.git ~/.zsh/pure
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-history-substring-search ~/.zsh/zsh-history-substring-search
git clone https://github.com/lukechilds/zsh-better-npm-completion ~/.zsh/zsh-better-npm-completion

Create the .zshrc file

The .zshrc file is used to configure the shell session and make use of the above scripts. Run the command:

nano ~/.zshrc

And paste in the following:

# --- STARTUP SYSTEM INFO (Linux interactive shells only) ---
if [[ -o interactive && "$(uname -s)" == "Linux" ]]; then
  echo

  # Header
  print -P "%F{cyan}=== System Info ===%f"

  # Core info
  print -P "Host:    %F{green}%m%f"
  print -P "User:    %F{green}%n%f"
  print -P "Uptime:  %F{green}$(uptime -p)%f"
  print -P "Kernel:  %F{green}$(uname -r)%f"

  # OS info (safe fallback if file missing)
  if [[ -r /etc/os-release ]]; then
    os=$(awk -F= '/^PRETTY_NAME=/ {gsub(/"/,"",$2); print $2}' /etc/os-release)
    print -P "OS:      %F{green}$os%f"
  fi

  # RAM usage
  ram=$(free | awk '/^Mem:/ {used=$3; total=$2; pct=int(used/total*100); printf "%.1f/%.1fG (%d%%%%)", used/1024/1024, total/1024/1024, pct}')
  print -P "RAM:     %F{green}$ram%f"
  # Root disk usage (cleaner parsing)
  disk=$(df -h / | awk 'NR==2 {print $3 "/" $2 " (" $5 "%)"}')
  print -P "Disk:    %F{green}$disk%f"
  # Inode usage
  inode=$(df -i / | awk 'NR==2 {gsub(/%/,"",$5); print $3 "/" $2 " (" $5 "%%)"}')
  print -P "Inodes:  %F{green}$inode%f"
  echo
fi

# --- PATH CUSTOMISATION ---
# Ensure ~/bin is at the front of PATH (and avoid duplicates)
typeset -U path
path=(~/bin $path)

# --- HISTORY SETTINGS ---
# File location and size limits for command history
HISTFILE=~/.zsh_history
HISTSIZE=5000      # commands kept in memory
SAVEHIST=5000      # commands saved to file

# Share history across all terminal sessions in real time
setopt SHARE_HISTORY

# Skip saving duplicate consecutive commands
setopt HIST_IGNORE_DUPS

# --- PURE PROMPT SETUP ---
# Add Pure prompt functions to fpath if installed, then enable Pure theme
if [[ -d "$HOME/.zsh/pure" ]]; then
  fpath+=("$HOME/.zsh/pure")
  autoload -U promptinit; promptinit
  prompt pure
fi

# --- COMPLETION SETTINGS ---
# Enable Zsh's programmable completion system
autoload -Uz compinit && compinit

# Make completion case-insensitive (e.g. "doc" → "Documents")
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'

# --- SSH HOST COMPLETION ---
# Populate SSH/SCP completion from ~/.ssh/config (ignore wildcard entries)
if [ -f ~/.ssh/config ]; then
  h=($(grep -i "^Host " ~/.ssh/config | grep -v "*" | awk '{print $2}'))
  zstyle ':completion:*:*:ssh:*:hosts' hosts $h
  zstyle ':completion:*:*:scp:*:hosts' hosts $h
fi

# --- COMPLETION UI TWEAKS ---
# Enable interactive selection menu and improve descriptions
zstyle ':completion:*:*:ssh:*' menu select
zstyle ':completion:*' verbose yes
zstyle ':completion:*:descriptions' format '%B--- %d ---%b'

# --- NPM COMPLETION ---
# Load enhanced npm completion if available
[[ -f ~/.zsh/zsh-better-npm-completion/zsh-better-npm-completion.plugin.zsh ]] && \
  source ~/.zsh/zsh-better-npm-completion/zsh-better-npm-completion.plugin.zsh

# --- HISTORY SUBSTRING SEARCH ---
# Allows up/down arrows to search history by current input
if [[ -f ~/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh ]]; then
  source ~/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh

  # Bind arrow keys (terminfo first, fallback sequences if needed)
  bindkey "$terminfo[kcuu1]" history-substring-search-up
  bindkey "$terminfo[kcud1]" history-substring-search-down
  bindkey '^[[A' history-substring-search-up
  bindkey '^[[B' history-substring-search-down
fi

# --- AUTOSUGGESTIONS ---
# Fish-style inline suggestions based on history
if [[ -f ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh ]]; then
  source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh

  # Subtle grey suggestion text
  ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'

  # This allows the right arrow to move the cursor AND accept suggestions
  bindkey '^[[C' forward-char
fi

# ---------------
# --- ALIASES ---
# ---------------

# --- Git helpers ---
alias gs='git status'
alias gd='git diff'
alias ga='git add'
alias gc='git commit'
alias gcm='git commit -m'
alias gl='git log --oneline --graph --decorate'
alias gp='git pull'
alias gps='git push'
alias gb='git branch'
alias gco='git checkout'

# File list helpers
alias ls='ls --color=auto'
alias ll='ls -lh --color=auto'
alias la='ls -lah --color=auto'

# --- OS-SPECIFIC HELPERS ---
case "$(uname -s)" in
  Darwin)
    # macOS
    alias ports='lsof -iTCP -sTCP:LISTEN -n -P'
    alias localip="ipconfig getifaddr en0"
    ;;
  Linux)
    # Linux
    alias ports='ss -tulpen'
    alias localip='hostname -I'
    ;;
esac

# Public IPv4 address
alias myip='curl -4 ifconfig.me && echo'

Set Z shell as the default shell

Enter the following command to set Z shell as your default shell:

chsh -s $(which zsh)

Note: you'll be prompted for your user password to confirm the change.

View as: JSON Markdown

If you enjoyed this post or found it useful, you can subscribe to my RSS feed.

More posts

  1. How to Launch WSL VS Code Projects from the Windows Start Menu

    A small PowerShell script for Windows that finds named WSL projects and creates Start Menu shortcuts to open them directly in Visual Studio Code using the WSL remote URI.

    windows wsl vscode claude ai
  2. Debian 13 (Trixie) server set-up

    A practical, production-ready guide to setting up a Debian 13 web server using Apache, PHP-FPM, and MariaDB. Covers installation, performance tuning, security basics, and modern best practices.

    debian apache mariadb php fail2ban ufw
  3. My MacBook Pro M5

    Fast, silent, and actually usable on your lap. I traded my ThinkPad for a MacBook Pro two months ago, and honestly? I should have done it sooner. Here is my honest take on the transition.

    apple hardware
  4. Flatspace Commander

    A love letter to the kid sitting on the floor in front of a CRT TV. Flatspace Commander is a minimalist, 1-bit space sim that brings back the tension of 80s wireframe trading with a modern, mobile twist.

    games pwa webdev
  5. PHOSPHOR: an entropy-based password generator

    I teamed up with Gemini and Claude to build a retro-futuristic password generator. It's a PWA that harvests hardware entropy from your movements, runs them through a SHA-256 math blender, and looks great doing it.

    pwa tools ai passwords
  6. PWA: Favicon & PWA Icon Generator

    I've taken my Favicon Generator entirely client-side. By leveraging the Canvas API, the new version handles all image processing right in your browser - no server required. With full offline support and new features like squircle shaping and individual icon overrides, it's a faster, more flexible way to manage your project assets.

    pwa tools images webdev
  7. Favicon & Manifest Generator

    Scratching a dev itch, I rebuilt my Favicon & Manifest generator. Upload one image to get all your PWA assets and a customisable manifest.json instantly.

    tools images webdev
  8. How to Launch VS Code Projects via macOS Spotlight

    I recently traded my Linux setup for a MacBook Pro, but I wasn't willing to give up my custom project launchers. With a little help from Claude, I've ported my original Bash script to macOS so I can open any project instantly using Cmd + Space.

    macos apple vscode spotlight
  9. Upgrading from Fedora 41 to Fedora 42

    If someone were to ask me which Linux distro has provided the best desktop experience, I wouldn't hesitate to answer: Fedora Workstation 41. So of course I upgraded to Fedora 42.

    fedora linux
  10. How to install PHP extension for Microsoft SQL Server under Fedora

    I found myself needing to connect to a Microsoft SQL Server via a PHP application running under Fedora. Finding concise details about installing the necessary drivers and extensions was not easy, so here is a blog post detailing how I did it.

    php microsoft fedora mssql sql linux
Loading…