できない.dev

Zsh で .zshrc に書いた PATH や alias が反映されない

Zsh は起動の種類によって読む設定ファイルを変える。.zshrc は対話シェルだけ、.zprofile はログインシェルだけ、.zshenv はすべてのシェルで読まれる。
反映されない原因はほぼ、書いた場所とシェルの種類の食い違いである。

公開:

要約

.zshrc に書いた設定が効かないとき、内容が間違っているのではなく そのシェルが .zshrc を読んでいない ことがほとんどである。
Zsh は起動ファイルを 1 本に決めておらず、シェルの種類ごとに読む対象を変える。

公式ドキュメントの定義は次のとおりである。

  • .zshenv … すべての Zsh で読まれる(非対話・非ログインを含む)
  • .zprofile … ログインシェルのときだけ、.zshrc より前に読まれる
  • .zshrc … 対話シェルのときだけ読まれる
  • .zlogin … ログインシェルのときだけ、.zshrc より後に読まれる

それぞれの直前にシステム全体版(/etc/zshenv/etc/zprofile/etc/zshrc/etc/zlogin)が読まれる点も重要で、PATH の順序が思ったとおりにならない場合はここが影響していることがある。

よくある原因

  1. Bash 用のファイルに書いている。.bashrc.bash_profile は Zsh からは読まれない。
    ログインシェルを Zsh に切り替えた直後に起きやすい。
  2. 非対話シェルから実行している。zsh -c 'コマンド'、cron、エディタのビルドタスクなどは対話シェルではないため .zshrc を読まない。
    「ターミナルでは通るのに CI やエディタからは command not found」という形で表面化する。
  3. ZDOTDIR が設定されている。
    設定されている場合、Zsh は $HOME ではなく $ZDOTDIR 配下の設定ファイルを読む。
  4. 読み込みの後段で上書きされている。
    ログインシェルではシステム側の起動ファイルが PATH を組み直すことがあり、.zshenv で先頭に置いたパスが後ろへ回る。

解決策

1. どのシェルなのかを確定する

[[ -o interactive ]] && echo interactive || echo non-interactive
[[ -o login ]] && echo login || echo non-login

対話かつログインなら .zprofile.zshrc の順に読まれている。
非対話なら .zshenv しか読まれていない。

2. 目的に応じて書く場所を選ぶ

# 対話操作のための設定(alias・プロンプト・補完)は .zshrc
echo 'alias ll="ls -la"' >> ~/.zshrc
 
# GUI アプリや非対話シェルにも渡したい環境変数は .zshenv
echo 'export EDITOR=vim' >> ~/.zshenv

PATH は迷ったら .zshrc に書く。
非対話シェルでも必要な場合だけ .zshenv に置く。

3. 実際に読まれた順序を確かめる

zsh -x -i -c exit 2>&1 | head -40

トレースに現れるファイル名が、そのシェルで実際に読まれたものである。
想定したファイルが出てこなければ、シェルの種類か ZDOTDIR を疑う。

4. 反映は再読み込みで行う

source ~/.zshrc

編集は既に開いているシェルには自動で反映されない。source するか、新しいターミナルを開く。

5. PATH の最終結果を見る

echo $PATH | tr ':' '\n'
which -a python3

意図した順序になっていなければ、.zshrc の末尾で明示的に組み直す。
Bash での同種の問題は Bash で PATH に追加したのに command not found が消えない にまとめてある。

この記事は役立ちましたか?