{
    "title": "My Z shell setup",
    "slug": "my-z-shell-setup",
    "excerpt": "A quick walkthrough of my Z shell setup for Debian servers and macOS, including Pure prompt, autosuggestions, history search, npm completion, SSH host completion, aliases, and a few cross-platform helper commands.",
    "body": "I've been a [Fish shell](https://en.wikipedia.org/wiki/Fish_(Unix_shell)) user for years. It was my shell of choice on my Linux systems until I purchased my [MacBook Pro](https://corenominal.com/blog/posts/my-macbook-pro-m5), when I switched to [Z shell](https://en.wikipedia.org/wiki/Z_shell).\n\nAs 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.\n\n## Install\n\nI 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.\n\n```\nsudo apt update\nsudo apt install zsh git curl\n```\n\n## Clone zsh scripts from GitHub\n\nRun the following commands to create a directory to hold the zsh scripts before cloning them from GitHub:\n\n```\nmkdir -p ~/.zsh\ngit clone https://github.com/sindresorhus/pure.git ~/.zsh/pure\ngit clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions\ngit clone https://github.com/zsh-users/zsh-history-substring-search ~/.zsh/zsh-history-substring-search\ngit clone https://github.com/lukechilds/zsh-better-npm-completion ~/.zsh/zsh-better-npm-completion\n```\n\n## Create the .zshrc file\n\nThe `.zshrc` file is used to configure the shell session and make use of the above scripts. Run the command:\n\n```\nnano ~/.zshrc\n```\n\nAnd paste in the following:\n\n```\n# --- STARTUP SYSTEM INFO (Linux interactive shells only) ---\nif [[ -o interactive && \"$(uname -s)\" == \"Linux\" ]]; then\n  echo\n\n  # Header\n  print -P \"%F{cyan}=== System Info ===%f\"\n\n  # Core info\n  print -P \"Host:    %F{green}%m%f\"\n  print -P \"User:    %F{green}%n%f\"\n  print -P \"Uptime:  %F{green}$(uptime -p)%f\"\n  print -P \"Kernel:  %F{green}$(uname -r)%f\"\n\n  # OS info (safe fallback if file missing)\n  if [[ -r /etc/os-release ]]; then\n    os=$(awk -F= '/^PRETTY_NAME=/ {gsub(/\"/,\"\",$2); print $2}' /etc/os-release)\n    print -P \"OS:      %F{green}$os%f\"\n  fi\n\n  # RAM usage\n  ram=$(free | awk '/^Mem:/ {used=$3; total=$2; pct=int(used/total*100); printf \"%.1f/%.1fG (%d%%%%)\", used/1024/1024, total/1024/1024, pct}')\n  print -P \"RAM:     %F{green}$ram%f\"\n  # Root disk usage (cleaner parsing)\n  disk=$(df -h / | awk 'NR==2 {print $3 \"/\" $2 \" (\" $5 \"%)\"}')\n  print -P \"Disk:    %F{green}$disk%f\"\n  # Inode usage\n  inode=$(df -i / | awk 'NR==2 {gsub(/%/,\"\",$5); print $3 \"/\" $2 \" (\" $5 \"%%)\"}')\n  print -P \"Inodes:  %F{green}$inode%f\"\n  echo\nfi\n\n# --- PATH CUSTOMISATION ---\n# Ensure ~/bin is at the front of PATH (and avoid duplicates)\ntypeset -U path\npath=(~/bin $path)\n\n# --- HISTORY SETTINGS ---\n# File location and size limits for command history\nHISTFILE=~/.zsh_history\nHISTSIZE=5000      # commands kept in memory\nSAVEHIST=5000      # commands saved to file\n\n# Share history across all terminal sessions in real time\nsetopt SHARE_HISTORY\n\n# Skip saving duplicate consecutive commands\nsetopt HIST_IGNORE_DUPS\n\n# --- PURE PROMPT SETUP ---\n# Add Pure prompt functions to fpath if installed, then enable Pure theme\nif [[ -d \"$HOME/.zsh/pure\" ]]; then\n  fpath+=(\"$HOME/.zsh/pure\")\n  autoload -U promptinit; promptinit\n  prompt pure\nfi\n\n# --- COMPLETION SETTINGS ---\n# Enable Zsh's programmable completion system\nautoload -Uz compinit && compinit\n\n# Make completion case-insensitive (e.g. \"doc\" → \"Documents\")\nzstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'\n\n# --- SSH HOST COMPLETION ---\n# Populate SSH/SCP completion from ~/.ssh/config (ignore wildcard entries)\nif [ -f ~/.ssh/config ]; then\n  h=($(grep -i \"^Host \" ~/.ssh/config | grep -v \"*\" | awk '{print $2}'))\n  zstyle ':completion:*:*:ssh:*:hosts' hosts $h\n  zstyle ':completion:*:*:scp:*:hosts' hosts $h\nfi\n\n# --- COMPLETION UI TWEAKS ---\n# Enable interactive selection menu and improve descriptions\nzstyle ':completion:*:*:ssh:*' menu select\nzstyle ':completion:*' verbose yes\nzstyle ':completion:*:descriptions' format '%B--- %d ---%b'\n\n# --- NPM COMPLETION ---\n# Load enhanced npm completion if available\n[[ -f ~/.zsh/zsh-better-npm-completion/zsh-better-npm-completion.plugin.zsh ]] && \\\n  source ~/.zsh/zsh-better-npm-completion/zsh-better-npm-completion.plugin.zsh\n\n# --- HISTORY SUBSTRING SEARCH ---\n# Allows up/down arrows to search history by current input\nif [[ -f ~/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh ]]; then\n  source ~/.zsh/zsh-history-substring-search/zsh-history-substring-search.zsh\n\n  # Bind arrow keys (terminfo first, fallback sequences if needed)\n  bindkey \"$terminfo[kcuu1]\" history-substring-search-up\n  bindkey \"$terminfo[kcud1]\" history-substring-search-down\n  bindkey '^[[A' history-substring-search-up\n  bindkey '^[[B' history-substring-search-down\nfi\n\n# --- AUTOSUGGESTIONS ---\n# Fish-style inline suggestions based on history\nif [[ -f ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh ]]; then\n  source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh\n\n  # Subtle grey suggestion text\n  ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'\n\n  # This allows the right arrow to move the cursor AND accept suggestions\n  bindkey '^[[C' forward-char\nfi\n\n# ---------------\n# --- ALIASES ---\n# ---------------\n\n# --- Git helpers ---\nalias gs='git status'\nalias gd='git diff'\nalias ga='git add'\nalias gc='git commit'\nalias gcm='git commit -m'\nalias gl='git log --oneline --graph --decorate'\nalias gp='git pull'\nalias gps='git push'\nalias gb='git branch'\nalias gco='git checkout'\n\n# File list helpers\nalias ls='ls --color=auto'\nalias ll='ls -lh --color=auto'\nalias la='ls -lah --color=auto'\n\n# --- OS-SPECIFIC HELPERS ---\ncase \"$(uname -s)\" in\n  Darwin)\n    # macOS\n    alias ports='lsof -iTCP -sTCP:LISTEN -n -P'\n    alias localip=\"ipconfig getifaddr en0\"\n    ;;\n  Linux)\n    # Linux\n    alias ports='ss -tulpen'\n    alias localip='hostname -I'\n    ;;\nesac\n\n# Public IPv4 address\nalias myip='curl -4 ifconfig.me && echo'\n```\n\n## Set Z shell as the default shell\n\nEnter the following command to set Z shell as your default shell:\n\n```\nchsh -s $(which zsh)\n```\n\n**Note:** you'll be prompted for your user password to confirm the change.",
    "tags": [],
    "published_at": "2026-04-27 17:45:00",
    "url": "https://corenominal.com/blog/posts/my-z-shell-setup",
    "featured_image": "https://corenominal.com/media/og-b4ef2860-577f-4426-bd3e-124a2ccd356c.png"
}