できない.dev

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

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

公開: 更新:

症状できない · exit 127
zsh -c 'mytool'
zsh:1: command not found: mytool
解決後できた · exit 0
zsh -c 'mytool'
mytool ok

2026-09-13 に alpine:3 で実際に打って取った出力。検証環境の詳細

要約

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

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

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

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

実行例

.zshrc に PATH を書いただけの状態では zsh -c 'mytool' が command not found で終了コード 127 になり、そのシェルは non-interactive と判定された。-i を付けて対話シェルとして起動するか、PATH を .zshenv にも書くと mytool ok が返り、zsh -x -i -c exit のトレースでは .zshenv の次に .zshrc が読まれている。

$ zsh -c 'mytool'
zsh:1: command not found: mytool
$ echo $?
127
$ zsh -c '[[ -o interactive ]] && echo interactive || echo non-interactive'
non-interactive
$ zsh -i -c 'mytool'
mytool ok
$ echo $?
0
$ zsh -c 'mytool'
mytool ok
$ echo $?
0
$ zsh -x -i -c exit 2>&1 | grep -E '\.z(shenv|profile|shrc)' | head -5
+/etc/zsh/zshenv:8> _x=( /root/.zshenv /root/.zshrc ) 
+/root/.zshenv:1> export PATH=/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+/root/.zshrc:1> export PATH=/root/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+/root/.zshrc:2> alias 'll=ls -la'

— 2026-09-13 時点の出力

検証環境2026-09-13 検証
検証日
実行環境
alpine:3 Alpine Linux v3.24

この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。

解決策

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 が消えない にまとめてある。

よくある原因

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

この手順で直った?