Macでパスを通す|コマンドが見つからないと言われたら
インストールしたはずのコマンドを打つと zsh: command not found が返る。検索して出てきた1行を .zshrc に貼り、ターミナルを開き直したら通った。この流れで解決してしまうと、次に同じことが起きたときにまた検索から始めることになります。Macでパスを通す作業は、やること自体は1行の追記です。それでも詰まる人が多いのは、macOSがPATHを何段階かに分けて組み立てていて、書き足す場所によって効く範囲が変わるからです。順番を押さえれば、その場で組み立てられるようになります。
PATHは探す場所の一覧で、通すとは1行足すこと
ターミナルでコマンド名だけを打ったとき、シェルはその名前のファイルをディスク全体から探すわけではありません。あらかじめ決められたディレクトリの一覧を順に見て、最初に見つかったものを実行します。この一覧がPATHという環境変数で、コロンで区切られた文字列として持たれています。
zshの説明書は、この変数をこう定義しています。コマンドを探すディレクトリの配列(コロン区切りの一覧)であり、この変数が設定されると各ディレクトリが走査され、見つかったファイルがすべてハッシュ表に入る、と書かれています。ここで重要なのは2点です。1つは「配列」という言葉で、zshではPATHと同じ中身を path という配列としても扱えること。もう1つは、一覧に入っていないディレクトリは、そこに実行ファイルがあっても名前だけでは呼べないということです。
つまりパスを通すとは、この一覧に自分が使いたいディレクトリを1つ足す作業です。ファイルを移動したり、権限を変えたり、何かをインストールし直したりする話ではありません。/usr/local/bin/mytool を mytool の3文字で呼べるようにするために、/usr/local/bin という文字列を一覧に加えるだけです。
一覧の順番には意味があります。同じ名前のコマンドが複数の場所にあるとき、先に書かれたディレクトリが勝ちます。Homebrewで新しいバージョンを入れたのに古いほうが動く、という現象はほぼこれが原因です。追加する位置を前にするか後ろにするかは、機能ではなく優先順位の指定になります。
macOSのPATHの土台は/etc/pathsとpath_helperが作っている
多くの解説記事は .zshrc の話から始まりますが、Macの場合、ターミナルを開いた時点でPATHにはすでに6つほどのディレクトリが入っています。これを組み立てているのは利用者が書いたファイルではなく、macOSに最初から入っている path_helper という小さなプログラムです。
path_helper の説明書は、動きをこう説明しています。まず /etc/paths と /etc/manpaths から既定値を読み、続いて /etc/paths.d と /etc/manpaths.d の中にあるファイルの内容をPATHとMANPATHに追記する。ディレクトリの中のファイルは1行に1つのパスを書く形式である、と決められています。さらに「このプログラムを直接呼び出すべきではない。シェルのプロファイルから使われることだけを想定している」と注意書きが付いています。
実際に呼び出しているのは /etc/zprofile です。このファイルには if [ -x /usr/libexec/path_helper ]; then eval \/usr/libexec/path_helper -s`; fiという数行だけが書かれていて、ログインシェルが起動するたびに実行されます。macOS 15の標準状態で/etc/pathsに並んでいるのは/usr/local/bin、/System/Cryptexes/App/usr/bin、/usr/bin、/bin、/usr/sbin、/sbin` の6つです。
ここを知っていると選択肢が1つ増えます。自分の環境だけでなく、そのMacを使う全員に効かせたいなら、/etc/paths.d/ に1行だけのファイルを置く方法があります。Homebrewが /etc/paths.d/homebrew に /opt/homebrew/bin と書いておく形がまさにそれです。ただしこの場所は管理者権限が必要で、path_helper は書かれた順に後ろへ追記するため、既存のシステムのパスより優先させることはできません。優先順位を自分で決めたいなら、次の節の方法を選びます。
書き足す先を決める。読まれる順番で効く範囲が変わる
zshの説明書は、起動時に読まれるファイルの順番を明記しています。最初に /etc/zshenv、次に ~/.zshenv。ログインシェルなら /etc/zprofile と ~/.zprofile。対話的シェルなら /etc/zshrc と ~/.zshrc。最後にログインシェルなら /etc/zlogin と ~/.zlogin です。
macOSで新しく作られるアカウントの既定のシェルは、Appleの説明によればzshです。
macOS 10.15以降では、Macのデフォルトのログインシェルおよびインタラクティブシェルとして、zshが使用されます。 出典: support.apple.com
古い記事が .bash_profile を指定しているのは、macOS 10.14以前の既定がbashだった時期に書かれたものです。いま .bash_profile に書いても、zshを使っている限り読まれません。初心者がつまずく最大の原因がここにあります。
書き先の選び方は単純です。ターミナルで使うだけなら ~/.zshrc で足ります。VS Codeの統合ターミナルやログイン直後の処理にも効かせたいなら ~/.zprofile に書きます。~/.zshenv はシェルが起動するたびに必ず読まれるため確実に見えますが、/etc/zprofile の path_helper があとから走るので、.zshenv に書いた追加分がシステムのパスより後ろに押しやられることがあります。並び順まで自分で決めたいときは .zprofile を選ぶのが素直です。
Appleの同じ説明でも、.zprofile は .bash_profile に相当してログイン時(SSHログインも含む)に実行され、.zshrc は対話的シェルのたびに実行されると整理されています。どちらか1つに決めて、両方に同じ行を書かないことが後の混乱を防ぎます。
実際の手順。無料の標準機能だけで終わる
必要な道具はMacに最初から入っているものだけで、追加の購入やインストールは要りません。手順は3つです。
1つ目は、追加したいディレクトリの正しい場所を確かめることです。目的の実行ファイルがある場所まで移動して pwd を打ち、表示された文字列をそのまま使います。Homebrewで入れたものなら、Apple Silicon搭載機では /opt/homebrew/bin、Intel搭載機では /usr/local/bin が既定です。Homebrewの公式文書は、インストーラーが既定の場所としてApple Siliconには /opt/homebrew、macOSのIntel機には /usr/local を使うと書いています。
2つ目は、設定ファイルに1行足すことです。export PATH="/opt/homebrew/bin:$PATH" のように書きます。前に足せば既存のコマンドより優先され、export PATH="$PATH:/opt/homebrew/bin" のように後ろに足せば既存のものが勝ちます。zshなら配列として path=(/opt/homebrew/bin $path) と書く形も使えます。
3つ目は、書いた内容を今開いているシェルに反映させることです。source ~/.zshrc を打つか、ターミナルのウインドウを新しく開きます。反映できたかは echo $PATH で一覧を見て、目的のディレクトリが入っているかを確かめます。
作業時間は慣れれば1分ほどで、失敗しても設定ファイルの1行を消せば元に戻ります。先にファイルをコピーして控えを取っておけば、書き間違えても取り返しがつきます。
通したのにcommand not foundが消えないときの見分け方
echo $PATH には入っているのに、まだコマンドが見つからないと言われる場合があります。原因はいくつかに分かれ、順に切り分けられます。
最初に確かめるのは、シェルが持っている記憶です。zshの説明書によれば、PATHが設定されると各ディレクトリが走査され、見つかったファイルがハッシュ表に入ります。この表は自動では作り直されないため、PATHを変える前から開いていたウインドウでは古い記憶が残ります。hash -r を打てば表が破棄され、rehash はその別名だと説明書に書かれています。新しいウインドウを開くのと同じ効果です。
次に確かめるのは、どれが実際に選ばれているかです。command -v コマンド名 と type -a コマンド名 は、シェルが選ぶ順番でその名前が解決される先を教えます。type -a は同じ名前が複数ある場合にすべて並べるので、意図しないほうが先に来ていることが一目で分かります。
見落としやすいのが、追記を繰り返して一覧が二重三重になっている状態です。zshには重複を自動で落とす指定があり、説明書は -U を「配列について、重複した値の最初の1つだけを残す」と定義したうえで、PATHのようにコロン区切りの特別な変数にも設定できると書いています。値を共有する変数では両方の名前に指定することが推奨されているため、typeset -U PATH path という形で書きます。
それでも見つからないときは、目的のファイルが実行できる状態かを確かめます。一覧の中にあっても、実行の許可が付いていないファイルはコマンドとして呼ばれません。ls -l で権限を見て、必要なら実行の許可を足します。
書き方の落とし穴と、PATHを壊さないための注意
PATHの設定で起きる事故のほとんどは、書き方の細部です。よくある間違いは3つに絞られます。
1つ目は $PATH の書き忘れです。export PATH="/opt/homebrew/bin" と書くと、それまでの一覧が全部消えて1つだけになります。この状態では ls も git も見つからなくなり、ターミナルがほとんど使えなくなります。設定ファイルを編集するためのエディタさえ呼べなくなるので、/usr/bin/vi ~/.zshrc のようにフルパスで呼んで直すか、新しいウインドウを開いて修正します。フルパスで書いたコマンドはPATHを参照せずに直接探されるため、こういう場面で確実に動きます。
2つ目はイコールの前後に空白を入れることです。PATH = "$PATH:/path" と書くと、シェルはこれを変数への代入ではなく PATH というコマンドの実行として読みます。代入の形では等号の左右に空白を入れられません。
3つ目は引用符の付け方です。パスに空白が含まれる場合、引用符で囲まないと途中で切れます。また、波括弧や記号が含まれる場所を二重引用符で囲むと展開されてしまうことがあるため、そのまま使いたい文字列は一重引用符を使うか、展開される文字を避けます。
もう1つ注意点があります。パスが通っていないこととインストールされていないことは別です。command not found が返ったからといって、まだ入っていないと判断して再インストールを繰り返すと、同じものが2か所に増えて優先順位の問題が新しく生まれます。先に ls で実体があるかを確かめ、あるならパスの問題として扱うのが順序です。
ターミナル以外から起動したものには、この設定が届かない
ここまでの設定はすべて、シェルが起動するときに読まれるファイルへの追記です。裏を返せば、シェルを経由しないで起動したものには何も届きません。FinderやDockからアプリを開いた場合、そのアプリはlaunchdから起動されるため、.zshrc や .zprofile は読まれません。
アプリの中から外部のコマンドを呼ぶ設計になっているとき、この差が症状として出ます。ターミナルでは動くのに、アプリのメニューから同じ処理を走らせると「コマンドが見つからない」と言われる。原因はPATHの設定ミスではなく、そもそも設定が読まれていないことです。
launchdが渡す環境変数は、launchctl の説明書によれば setenv key value で指定でき、呼び出し元のコンテキストで以降に起動されるすべてのプロセスに設定されます。getenv key で現在の値を確認でき、unsetenv key で外せます。ただしこの指定は再起動すると消えるため、恒久的にしたい場合は起動時に走る仕組みを別に用意することになります。
現実的な回避策は2つです。アプリの設定にコマンドの場所を入れる欄があるなら、フルパスで指定するほうが確実です。アプリ側が使うシェルを指定できるなら、ログインシェルとして起動する指定にすれば設定ファイルが読まれます。どちらも用意されていない場合だけ、launchd側に環境変数を渡す話になります。
確かめる作業が窓をまたぐという問題
パスを通す作業そのものは1行です。時間を食うのは、その前後の確認です。目的の実行ファイルがどこにあるかをフォルダの一覧で探し、パスを写し取り、ターミナルに切り替えて設定ファイルを開き、書き足して、反映して、echo $PATH の出力を読む。さらに動かなければ type -a を打ち、権限を見るために一覧に戻る。
工程を数えると、実際に手を動かす回数よりも、窓を切り替える回数のほうが多くなります。ファイルの場所を見る画面とコマンドを打つ画面が別のアプリだと、片方で見た文字列をもう片方に持ち込むだけで数秒かかり、それを何度も繰り返します。AIに聞いて答えをもらう場合も、また別の窓が増えます。
ここで効くのは、より短いコマンドを覚えることではありません。フォルダとターミナルとAIが同じ窓にある状態にして、一覧で選んだディレクトリのパスをそのままコマンドに渡し、出力を同じ画面で読めるようにすることです。パス周りの作業のように「見て、書いて、また見る」を繰り返す工程では、往復の回数がそのまま所要時間になります。
ターミナルを内蔵したファイル管理で何がどこまでできるのかはできることに一覧があり、標準のFinderや他のアプリとの違いは他のファイル管理との比較に整理してあります。Macに置いたまま出先から続きを確かめる使い方はiPhone・iPadから続きをが該当し、費用の考え方は料金、導入前に迷いやすい点はよくある質問にまとめられています。
パスを通す手順自体は20年以上ほとんど変わっていません。変わったのは既定のシェルと、Homebrewの置き場所と、確認のために開く窓の数です。前の2つは調べれば分かります。3つ目だけが、いまも作業時間を押し上げたまま残っています。
よくある質問
.zshrcと.zprofileは、どちらに書けばよいですか?
ターミナルで打つコマンドのために通すだけなら ~/.zshrc で足ります。ログイン時に1度だけ読ませたい設定や、エディタの統合ターミナルにも効かせたい場合は ~/.zprofile を選びます。両方に同じ行を書くと一覧が二重になるため、どちらか1つに決めます。.bash_profile は現在の既定のシェルでは読まれません。
書き足したのに反映されません。何を確かめればよいですか?
まず source ~/.zshrc を打つか、ターミナルの新しいウインドウを開きます。次に echo $PATH で目的のディレクトリが入っているかを見ます。入っているのに見つからないと言われる場合は hash -r でシェルの記憶を破棄し、type -a コマンド名 でどこが選ばれているかを確かめます。
パスを通すのに費用はかかりますか?
かかりません。必要なのはターミナルとテキストエディタで、どちらもmacOSに最初から入っています。追加のアプリも管理者権限も原則として要りません。/etc/paths.d/ に置いてMac全体に効かせる方法だけは管理者権限が必要です。
設定を間違えてコマンドが全部使えなくなりました。どう戻しますか?
$PATH を付け忘れて上書きすると既存の一覧が消えます。その状態でも、フルパスで呼んだコマンドはPATHを参照しないため動きます。/usr/bin/vi ~/.zshrc や /usr/bin/nano ~/.zshrc で該当の行を消し、ターミナルを開き直せば元に戻ります。設定ファイルを触る前に別名でコピーしておくと、この作業がさらに短くなります。