⛳
PATHと環境変数の超入門(Mac / Windows / WSL)— “コマンドが見つからない”を根絶する
ねらい:command not found や “別のPythonが動く” を根本から防ぎ、どのPCでも同じ挙動を出す。
対象:AI/WEB開発の初〜中級者/チーム開発者。
ゴール:PATHと環境変数を安全に追加・確認・共有できる。
TL;DR(まずはこれだけ)
- PATHは“左から順に”検索される(左が勝つ)。追加は先頭にprependが基本。
-
設定ファイルは場所を間違えない(Macは
.zprofileと.zshrc、WindowsはUser PATHが安全)。 -
現セッションで動いても永続しないことがある(Windowsの
setxは新しいシェルから有効)。 -
機密は
.envに分離、リポジトリには**.env.exampleのみ**を置く。
1) まず“今”の状態を確認する
共通(どのOSでも)
# どのPython/どのpipが使われているか
python -c "import sys;print(sys.executable)"
python -m pip --version
# PATHを1行ずつ見る(macOS/Linux/WSL)
echo "$PATH" | tr ':' '\n' | nl
Windows(PowerShell)
# どのpythonか
(Get-Command python).Source
# PATHを1行ずつ
$env:PATH -split ';' | % {$_} | % {$i=0}{++$i; "$i`t$_"}
原則:失敗の8割は“想定外の実行器”が先頭にあること。順序を可視化してから直す。
2) macOS(zsh)の正しい置き場所と書き方
-
どこに書く?
-
~/.zprofile:ログイン時に1回だけ読ませたいもの(PATHの初期化)。 -
~/.zshrc:毎回の対話シェルで読みたいもの(エイリアス、関数、補完など)。 - HomebrewはIntel/M1でパスが違うので分岐する。
-
推奨スニペット(貼るだけ)
# ~/.zprofile ← PATHの初期化はこっち
# Homebrew
if [[ -d /opt/homebrew/bin ]]; then
eval "$(/opt/homebrew/bin/brew shellenv)" # Apple Silicon
elif [[ -d /usr/local/bin ]]; then
export PATH="/usr/local/bin:$PATH" # Intel
fi
# よく使うローカルbinを先頭に(重複追加を防ぐ)
prepend_path () { case ":$PATH:" in *":$1:"*) ;; *) export PATH="$1:$PATH";; esac }
prepend_path "$HOME/.local/bin"
prepend_path "$HOME/.poetry/bin"
# ~/.zshrc ← 対話設定はこちら
# 補完やエイリアスなど
autoload -U compinit && compinit
alias ll='ls -alF'
# PATHの見える化(任意)
path() { echo "$PATH" | tr ':' '\n' | nl; }
-
反映:新しいターミナルを開くか、
exec $SHELL -l(ログインとして再起動)。 -
アンチパターン:
.zshrcと.zprofileの両方でPATHを上書き → 順序が壊れる。
3) Windowsの基本(User PATHを安全に)
-
スコープの違い
- Process(現在のシェルだけ)
- User(自分のアカウント全体)←まずはこれ
- System(全ユーザ)←管理者用途。失敗時の影響が大きいので避ける
一時的に試す(現セッションのみ)
# 先頭に追加(再起動不要・セッション限定)
$env:Path = "C:\Users\<you>\AppData\Local\Programs\Python\Python39\Scripts;" + $env:Path
永続化(ユーザPATHへ・安全版)
# 既存のUser PATHを取得
$u = [Environment]::GetEnvironmentVariable('Path','User')
# 追記(重複チェックは必要に応じて)
$new = "C:\Tools\bin;$u"
[Environment]::SetEnvironmentVariable('Path',$new,'User')
- 反映:新しいPowerShellを開く(既存セッションには効かない)。
-
注意:
setxは簡単だが長いPATHを切り詰めることがある。上の .NET API 方式が安全。 -
スペースを含むパス:
"C:\Program Files\Git\cmd"のように必ず二重引用符で扱う。
4) WSL2(Windows上のLinux)でのコツ
-
プロジェクトはLinux側に置く:
\\wsl$\Ubuntu\home\<you>\project(/mnt/c/...はI/Oが遅い)。 -
Windows PATHの混入を制御(再現性重視):
/etc/wsl.conf(ディストロ内)に追記 →wsl --shutdown→ 再起動。
[interop]
appendWindowsPath=false
[automount]
options="metadata,umask=22,fmask=11" # 権限の整合を取りやすくする
-
DNSや時計ズレでネット/証明書が失敗することがある →
wsl --status/wsl --updateで更新、Windows側の時刻同期。
5) 環境変数の扱い(.env / 12-Factor)
-
原則
-
秘密はコードに直書きしない。
.envに置く。 - リポジトリには
.envをコミットしない、代わりに.env.exampleを置く。 - 本番はOSの環境変数やシークレットマネージャで注入。
-
秘密はコードに直書きしない。
最小雛形
# .env (コミットしない)
DATABASE_URL=postgres://user:pass@localhost:5432/app
SECRET_KEY=change-me
# .env.example (コミットする)
DATABASE_URL=postgres://user:pass@localhost:5432/app
SECRET_KEY=__FILL_THIS__
-
Python(ローカル実行):
python-dotenvで読み込む。
# app.py
from dotenv import load_dotenv; load_dotenv()
# os.environ['SECRET_KEY'] が使える
-
Docker Compose:composeファイルと同じディレクトリの
.envが自動読込。実際に反映された値はdocker compose configで確認。
6) “順序”と“競合”の落とし穴(典型パターン)
-
別のPythonが先頭にいる
- 例:Xcode付属のPython、旧Anaconda、古い
/usr/local/bin/pythonなど - 対処:PATH順序を入れ替えるか、実行は常に
python -mで。
- 例:Xcode付属のPython、旧Anaconda、古い
-
同名コマンドの多重インストール
- 例:
pipが3つある → 何が先かwhich -a pip/Get-Command pip -Allで洗い出す - 対処:
python -m pip原則で回避。
- 例:
-
改行コード(CRLF)でスクリプトが動かない(WSL/mac)
- 対処:
.gitattributesでeol=lf、既存はdos2unix。
- 対処:
-
設定を上書き合っている
- 例:
.zprofileと.zshrc、複数のsetx、複数の.env - 対処:“どこに何を書くか”を決めてドキュメント化。被らせない。
- 例:
7) チームで共有する“安全テンプレ”
macOS(貼るだけ)
# ~/.zprofile
if [[ -d /opt/homebrew/bin ]]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [[ -d /usr/local/bin ]]; then
export PATH="/usr/local/bin:$PATH"
fi
prepend_path () { case ":$PATH:" in *":$1:"*) ;; *) export PATH="$1:$PATH";; esac }
prepend_path "$HOME/.local/bin"
prepend_path "$HOME/.poetry/bin"
Windows(PowerShellスクリプト)
# add-path.ps1
param([string]$NewPath)
$u = [Environment]::GetEnvironmentVariable('Path','User')
if ($u -notlike "*$NewPath*") {
[Environment]::SetEnvironmentVariable('Path', "$NewPath;$u", 'User')
"Added to User PATH: $NewPath`nRestart the terminal."
} else { "Already present: $NewPath" }
.gitattributes(改行の地雷排除)
*.sh text eol=lf
*.py text eol=lf
Dockerfile text eol=lf
8) 診断の順番(困ったらこれ)
-
実行器の特定:
sys.executable/Get-Command python -
PATHの並びを見る:
tr ':' '\n'/-split ';' -
仮想環境の有効化:
source .venv/bin/activate/.\.venv\Scripts\activate -
python -m原則で再実行:python -m pip,python -m pytest -
設定ファイルを最小化:
.zprofileだけで再現 → 問題切り分け -
WSLなら置き場所を確認:Linux側か?
metadata有効か? - 新しいシェルで確認:Windowsは特に再起動必須
まとめ(今日からの運用)
- PATHは先頭勝ち。追加はprepend、重複防止の関数で。
-
設定の責務分離:macOSは
.zprofile(PATH)と.zshrc(対話)、WindowsはUser PATH中心。 -
機密は
.env、リポジトリは**.env.example**で共有。 - 迷ったら**実行器の可視化→PATHの順序→
python -m**で切り分け。
Discussion