Zsh 模組化配置
Zsh 模組化配置
Shell 配置是 dotfile 管理裡最基礎也最常失控的一層。.zshrc 或 .bashrc 通常是開發者第一個開始客製的檔案,也是最容易長成數百行無結構巨檔的對象。
Zsh vs Bash 的配置檔載入順序
理解配置檔的載入順序是結構化拆分的前提。不知道哪個檔案在什麼時機被讀取,就無法判斷設定該放在哪。
Bash 的載入順序
Bash 區分 login shell 和 non-login shell,兩者讀取的檔案不同:
- Login shell(SSH 進來、
bash --login):讀~/.bash_profile(如果不存在,依序嘗試~/.bash_login→~/.profile) - Non-login interactive shell(開一個新終端機視窗):讀
~/.bashrc - 常見做法:在
~/.bash_profile裡 source~/.bashrc,確保設定不管怎麼進來都一致
Zsh 的載入順序
Zsh 的載入鏈比 Bash 更細緻:
~/.zshenv— 每次都讀(login、non-login、script 都會),放環境變數~/.zprofile— 只有 login shell 讀,對應 Bash 的~/.bash_profile~/.zshrc— interactive shell 讀,放 alias、function、prompt、plugin~/.zlogin— login shell 在.zshrc之後讀(少用)~/.zlogout— logout 時讀(少用)
實務上 90% 的設定都進 .zshrc,環境變數(PATH、EDITOR)放 .zshenv。
結構化拆分:從單一巨檔到模組化
一個典型的失控 .zshrc 長這樣:PATH 設定、alias、function、plugin 載入、prompt 配置、各種工具的 eval/source 全混在一起,改一個東西要在五百行裡找位置。
模組化的目標是依職責拆檔,.zshrc 本身只負責 source 這些模組:
1# ~/.zshrc — 只做 source,不放具體設定
2
3# 環境變數(PATH 在 .zshenv,這裡放其他 interactive 專用的)
4source "$HOME/.config/zsh/env.zsh"
5
6# Alias
7source "$HOME/.config/zsh/aliases.zsh"
8
9# Function
10source "$HOME/.config/zsh/functions.zsh"
11
12# Plugin manager
13source "$HOME/.config/zsh/plugins.zsh"
14
15# Prompt / theme
16source "$HOME/.config/zsh/prompt.zsh"
17
18# 工具整合(fzf, nvm, pyenv, etc.)
19source "$HOME/.config/zsh/tools.zsh"
20
21# 機器專屬設定(不進 Git)
22[[ -f "$HOME/.config/zsh/local.zsh" ]] && source "$HOME/.config/zsh/local.zsh"各模組的職責
aliases.zsh — 短指令對映
1# 檔案操作
2alias ll='ls -alF'
3alias la='ls -A'
4
5# Git 常用
6alias gs='git status'
7alias gd='git diff'
8alias gco='git checkout'
9alias gp='git push'
10
11# 導航
12alias ..='cd ..'
13alias ...='cd ../..'判讀準則:alias 適合「不帶參數的簡單替換」。如果需要參數處理或條件判斷,改用 function。
functions.zsh — 帶邏輯的常用操作
1# 建目錄並進入
2mkcd() {
3 mkdir -p "$1" && cd "$1"
4}
5
6# 在 Git repo 根目錄搜尋
7ggrep() {
8 git grep "$@" "$(git rev-parse --show-toplevel)"
9}tools.zsh — 第三方工具的初始化
1# fzf
2[[ -f ~/.fzf.zsh ]] && source ~/.fzf.zsh
3
4# nvm
5export NVM_DIR="$HOME/.nvm"
6[[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh"
7
8# pyenv
9command -v pyenv >/dev/null && eval "$(pyenv init -)"每個工具的 init 前面加存在性檢查(command -v 或 [[ -f ]]),避免在沒裝該工具的機器上報錯。
local.zsh — 機器專屬、不進 Git
1# 公司 VPN 設定
2export CORP_PROXY="http://proxy.corp:8080"
3
4# 只有這台機器需要的 PATH
5export PATH="$HOME/corp-tools/bin:$PATH"在 dotfile repo 的 .gitignore 裡排除這個檔案。.zshrc 裡用 [[ -f ... ]] && source 確保不存在也不報錯。