環境変数の export と PATH:.zshrc での書く順番に注意

スポンサーリンク

環境変数の export と PATH:.zshrc での書く順番に注意

.zshrc.bashrc でツールのパスを設定するとき、書く順番によって export が正常に機能しないことがあります。


問題のある設定例

# NG: この時点で mise は PATH に入っていないので失敗する
export MISE_ROOT=$(mise root)        # command not found: mise

# mise を PATH に追加するのはここ(遅い)
export PATH="$HOME/.local/bin:$PATH"

$(mise root) を評価しようとした時点では mise はまだ PATH に存在しません。結果として MISE_ROOT は空のまま、またはエラーになります。


なぜこうなるのか

.zshrc はシェル起動時に上から順に実行されます。コマンド置換 $(...) はその行が評価されるタイミングで即座に実行されるため、まだ PATH に追加されていないコマンドは command not found になります。

シェル起動
  ↓
1行目: export HOGE=$(func)           ← この時点の PATH でコマンドを探す
  ↓                                     → func が見つからず HOGE は空になる
2行目: export PATH="$HOME/bin:$PATH" ← ここで func が PATH に追加される
  ↓
(1行目はすでに実行済み。HOGE は空のまま変わらない)

正しい書き方:PATH を先に設定する

コマンド置換を使う export は、そのコマンドが PATH に入った後に書く。

# OK: PATH を先に設定してから使う
export PATH="$HOME/.local/bin:$PATH"

# mise が PATH に入っているのでコマンド置換が正常に動く
export MISE_ROOT=$(mise root)

よくある実例

Homebrew(macOS)

# NG
export HOMEBREW_PREFIX=$(brew --prefix)    # brew が PATH にない
eval "$(/opt/homebrew/bin/brew shellenv)"  # ここで brew が PATH に入る(遅い)

# OK
eval "$(/opt/homebrew/bin/brew shellenv)"  # 先に brew を PATH に追加
export HOMEBREW_PREFIX=$(brew --prefix)    # これで brew が使える

Go

# NG
export GOPATH=$(go env GOPATH)         # go が見つからない
export PATH="$PATH:/usr/local/go/bin"  # ここで go が PATH に入る(遅い)

# OK
export PATH="$PATH:/usr/local/go/bin"  # 先に go を PATH に追加
export GOPATH=$(go env GOPATH)         # これで go env が使える

pyenv / rbenv

# NG
eval "$(pyenv init -)"                  # pyenv が見つからない
export PATH="$HOME/.pyenv/bin:$PATH"   # ここで pyenv が PATH に入る(遅い)

# OK
export PATH="$HOME/.pyenv/bin:$PATH"   # 先に pyenv を PATH に追加
eval "$(pyenv init -)"                  # これで pyenv init が使える

絶対パスを使えば順番に依存しない

コマンドを絶対パスで指定すれば PATH に関係なく動作します。ただし環境依存になるため、インストール先が固定されているツールに限って使うのが無難です。

# 絶対パスなら順番に関係なく動く
export HOMEBREW_PREFIX=$(/opt/homebrew/bin/brew --prefix)

まとめ

パターン 結果
PATH に追加する$(cmd) を使う command not found / 変数が空になる
PATH に追加した$(cmd) を使う 正常に動作する
絶対パスで呼ぶ $(/usr/bin/cmd) 順番に関わらず動作する

.zshrc のデバッグには echo $PATH を途中に挟んで、その時点で PATH に何が入っているか確認するのが確実です。

mise を使ったバージョン管理については「miseでRubyをインストールする方法:.ruby-versionの使い方」も参照してください。