.zshrcの設定見直しで発見した4つの問題と修正方法

4 Common .zshrc Configuration Issues and How to Fix Them

* 本ページはプロモーションが含まれています

ZshとNeoVimの設定見直し で設定したZshrcをベースにして愛用してきましたが、生成AI(ChatGPT-5.2)の力を借りて設定を見直した。

改善点 

  • 壊れてた判定関数を正しく(return $(…) をやめる)
  • localeは触らない(LC_ALL は特に事故りやすい)
  • 補完は初回から効くように(zinit遅延ロード×compinit順序の地雷回避)
  • 重い一覧は ll/la に隔離して、普段の ls を遅くしない

背景:.zshrc は「便利」と「破壊」が紙一重 

zshrcの改善って、見た目やalias追加よりも「間違った書き方が静かに壊す」系の地雷が多い。今回ハマりどころだったのはこの4つ:

  1. _has/_try の return $(…)
  2. locale(LC_ALL の上書き)
  3. zinit の遅延ロードと compinit の順序
  4. ls 相当を重くしすぎる alias

1) _has/_try: return $(…) は“出力を終了ステータスにする”事故 

return が返すのは 0〜255 のステータス。ここに $(…) の標準出力を食わせると、空文字/文字列になって壊れる(意図とズレる)。

修正はシンプルで、「そのコマンドを実行して終了ステータスを返す」だけ。

_has() {
  whence -w -- "$1" >/dev/null 2>&1
}

_try() {
  eval "$*" >/dev/null 2>&1
}

ポイント:

  • “$1” / “$*” は必ずクォート(空白や特殊文字で壊れるのを防ぐ)
  • _try は eval なので使い所は限定(今回は既存設計を崩さず安全側に寄せた)

2) locale:LC_ALL は“全部上書き”なので .zshrc で触らない 

一度 LC_ALL をexportすると、LC_CTYPE や LC_MESSAGES など全カテゴリが強制される。結果として日本語が化ける・コマンドの出力が変わる・想定外の挙動になる。

今回は .zshrc 内で LC_ALL は設定しない方針にして、LANG が空なら UTF-8 を入れるだけにした。

if [[ -z ${LANG-} ]]; then
  export LANG=ja_JP.UTF-8
fi

# NOTE:
# Avoid setting LC_ALL here. It overrides all LC_* categories and can easily
# cause mojibake. If you need C locale for a single command, do:
#   LC_ALL=C <cmd>

運用tips:

  • 「ソートだけCでやりたい」みたいな用途は、そのコマンドだけ LC_ALL=C cmd にするのが安全。

3) 補完:zinit遅延ロードとcompinitの順序で“初回だけ効かない”が起きる 

補完ソース(例:zsh-completions)を遅延ロードしておいて、先に compinit を走らせると、初回だけ補完が微妙になることがある。

今回は補完系は遅延しないで先に読み、compinit -C(キャッシュ)で軽くした。

zinit light zsh-users/zsh-completions
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
zstyle ':completion:*:default' menu select=1

autoload -Uz compinit && compinit -C

4) alias:重い ls 互換は ll/la に隔離 

eza のオプション盛り盛り(icons/git/time-style/all/long)は気持ちいいけど、ディレクトリが大きいと普通に遅い。

なので「重いのは明示コマンドへ」で、ll/la を生やした。

which eza > /dev/null && alias ll='eza --icons --git --time-style relative -al'
which eza > /dev/null && alias la='eza --icons --git --time-style relative -a'

ついでに潰した地雷:スマートクォートで alias が死ぬ 

alias dc=‘docker-compose’ みたいなスマートクォート混入は、その行だけ無効になるやつ。ASCII ’ に統一した上で、docker v2優先のフォールバックにした。

if _has docker; then
  if _try "docker compose version"; then
    alias dc='docker compose'
  elif _has docker-compose; then
    alias dc='docker-compose'
  fi
fi

検証:最低限これだけ 

  • 文法チェック(副作用なし)
zsh -n ~/.zshrc
  • 反映(新しい環境で評価)
exec zsh -l

※ 文字化けが出た時は「古いシェル/ターミナルが古い環境を保持してた」ことがあるので、必要ならターミナル再起動。


まとめ 

  • .zshrc は “便利さ” より先に 壊れないこと を優先した方が、結局気持ちよく使える
  • LC_ALL は局所化、補完は順序、重い表示は ll/la に逃がす
  • return $(…) は論外(出力≠終了ステータス)

参考 


See also