Skip to main content

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'

  # Accept suggestion with right arrow
  bindkey '^[[C' autosuggest-accept
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.

Similar posts

  1. 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
  2. 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
  3. 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
  4. GNOME menu entries for Visual Studio Code projects

    I work on a large number of code projects and I wanted a quick way to open any of my projects in Visual Studio Code, my preferred code editor. I figured the quickest way to do this under GNOME would be to create a .desktop file for each project directory.

    gnome vscode linux
  5. My Debian 12 (bookworm) server set-up

    I've been running Debian on my servers for years. It's dependable. I guess my server set-up is pretty common, consisting of Apache, PHP and MariaDB, but I figure it is still worth sharing details of how I provision my servers.

    php composer mariadb apache debian linux node fish
  6. My Debian 12 (bookworm) desktop set-up

    Creating a good Debian desktop experience is not too difficult, thanks to the excellent work of the Debian developers, but I thought it might be interesting to share how I set-up my Debian systems.

    debian linux
  7. Upgrading from Fedora 40 to Fedora 41

    A post describing my first experience of upgrading a Fedora installation. TLDR: The upgrade went smoothly and Fedora continues to impress me.

    fedora linux
  8. Desktop Linux and compiling from source

    If anyone is in any doubt as to whether you need to compile any software from source in order to use desktop Linux, you really don't.

    linux
  9. Switching desktop Linux from Debian to Fedora

    Last week I switched the operating system on my daily driver (Lenovo ThinkPad T14s) from Debian 12 to Fedora 40. In this post I write a little about why I switched and how the switch went.

    debian linux fedora
  10. How to create Bash aliases in Fedora

    Creating your own Bash aliases is a relatively easy process. That said, I recently switched my desktop linux distribution from Debian to Fedora and there are subtle differences.

    linux fedora debian bash
  11. How to set-up a crontab file

    In Linux, Cron is a daemon/service that executes shell commands periodically on a given schedule. Cron is driven by a crontab, a configuration file that holds details of what commands are to be run along with a timetable of when to run them. Knowing how to use Cron is key to mastering automation with Linux.

    cron automation linux