How to add a directory to your PATH

Julia Evans

PATHにディレクトリを追加する方法

今日、友人とPATHにディレクトリを追加する方法について話していました。長年ターミナルを使ってきたので、自分にとっては「当たり前」のことのように感じますが、実際にやり方を検索してみると、すべての手順をきちんと説明してくれているものがなかなか見つかりませんでした。多くは「これを~/.bashrcに追加してください」と書いてあるだけです。でも、bashを使っていなかったらどうするのでしょう? bashの設定ファイルが別の場所にあったら?そもそも、どのディレクトリを追加すればいいのか、どうやって判断すればいいのでしょうか?

そこで、もう少し完全な手順をまとめて、これまでに自分がはまってきた落とし穴についても書いてみようと思いました。

ステップ1:使っているシェルを確認する

使っているシェルがわからない場合は、次のコマンドを実行してみてください。

ps -p $$ -o pid,comm=
  • bashを使っている場合は、97295 bashのように表示されます
  • zshを使っている場合は、97295 zshのように表示されます
  • fishを使っている場合は、「In fish, please use $fish_pid」のようなエラーが表示されます($$はfishでは正しい構文ではないためです。とはいえ、このエラーメッセージが出ればfishを使っていることがわかります。おそらくすでにご存知かと思いますが)

なお、Linuxではbashが、Macでは(2024年現在)zshがデフォルトです。この記事ではbash、zsh、fishのみを扱います。

ステップ2:シェルの設定ファイルを見つける

  • zshの場合は、おそらく~/.zshrcです
  • bashの場合は~/.bashrcかもしれませんが、少し複雑なので次のセクションの注意書きをご覧ください
  • fishの場合は、おそらく~/.config/fish/config.fishです(確実に知りたい場合はecho $__fish_config_dirを実行してください)

bashの設定ファイルについての注意

Bashには3つの設定ファイルが考えられます。~/.bashrc~/.bash_profile、そして~/.profileです。

どれが使われているかわからない場合は、次のように試すのがおすすめです。

  1. ~/.bashrcecho hi thereと書き加えます
  2. ターミナルを再起動します
  3. 「hi there」と表示されれば、~/.bashrcが使われているということです!やった!
  4. 表示されなければ、その行を削除して、同じことを~/.bash_profileで試してみてください
  5. 最初の2つでうまくいかなければ、~/.profileでも試してみてください。

(bashがどの設定ファイルを使うかを説明した精緻なフローチャートはたくさんありますが、個人的には覚える価値はないと思います。実際に試してみるのが一番早くて確実です)

ステップ3:追加すべきディレクトリを特定する

たとえば、http-serverというプログラムをインストールして実行しようとしたのに、うまくいかないとします。例えばこんな感じです。

$ npm install -g http-server
$ http-server
bash: http-server: command not found

http-serverがどのディレクトリにあるのか、どうやって見つければいいのでしょうか。正直なところ、これは一般的にそれほど簡単ではありません。答えは「npmの設定による」といった具合であることが多いからです。いくつかヒントを挙げます。

  • 新しいインストーラー(cargonpmhomebrewなど)を初めてセットアップする際に、PATHの更新方法についての案内が表示されることがよくあります。そのタイミングでよく見ておけば、手順を入手できます。
  • インストーラーが自動的にシェルの設定ファイルを更新して、PATHを追加してくれることもあります
  • 単純に「where does npm install things?」のように検索するだけで答えが見つかることもあります
  • どこにインストールされるかを教えてくれるサブコマンドを用意しているツールもあります。例えば次のようなものです。
    • Node/npm: npm config get prefix(その結果に/bin/を付け足します)
    • Go: go env GOPATH(その結果に/bin/を付け足します)
    • asdf: asdf info | grep ASDF_DIR(その結果に/bin//shims/を付け足します)

ステップ3.1:正しいディレクトリか確認する

正しそうなディレクトリが見つかったら、本当に合っているか確認しましょう!例えば、私のマシンではhttp-server~/.npm-global/binにありました。次のように、そのディレクトリにあるプログラムを直接実行してみることで確認できます。

$ ~/.npm-global/bin/http-server
Starting up http-server, serving ./public

うまくいきました!PATHに追加すべきディレクトリがわかったので、次のステップに進みましょう!

ステップ4:シェルの設定ファイルを編集する

これで、必要な2つの重要な情報が揃いました。

  1. PATHに追加したいディレクトリ(例:~/.npm-global/bin/
  2. シェルの設定ファイルの場所(例:~/.bashrc~/.zshrc、または~/.config/fish/config.fish

何を追記するかは、使っているシェルによって異なります。

bashの場合:

シェルの設定ファイルを開いて、次のような行を追加してください。

export PATH=$PATH:~/.npm-global/bin/

(もちろん~/.npm-global/binの部分は、実際に追加したいディレクトリに置き換えてください)

zshの場合:

bashと同じ書き方でも構いませんが、zshでは好みに応じて少し凝った次のような書き方も使えます。

path=(
  $path
  ~/.npm-global/bin
)

fishの場合:

fishでは構文が異なります。

set PATH $PATH ~/.npm-global/bin

(fishではfish_add_pathを使うこともできます。詳しくは後述します)

ステップ5:シェルを再起動する

ここで、非常に重要なステップです。シェルの設定ファイルを更新しても、再起動しなければ反映されません!

方法は2つあります。

  1. 新しいターミナル(またはターミナルの新しいタブ)を開きます。混乱しないように、古い方は閉じておくとよいでしょう
  2. bashを実行して新しいシェルを起動します(zshを使っているならzsh、fishならfishです)

どちらの方法でもだいたいうまくいきます。

これで完了です!実行したかったプログラムをもう一度試してみてください。今度はきっと動くはずです。

うまくいかない場合は、次のような問題が考えられます。

問題1:違うプログラムが実行されてしまった

違うバージョンのプログラムが動いてしまった場合は、ディレクトリをPATHの末尾ではなく、先頭に追加する必要があるかもしれません。

例えば、私の環境には2つのバージョンのpython3がインストールされており、which -aで確認できます。

$ which -a python3
/usr/bin/python3
/opt/homebrew/bin/python3

シェルが実際に使うのは、一番最初に表示されたものです。

Homebrew版を使いたい場合は、そのディレクトリ(/opt/homebrew/bin)をPATHの先頭に追加する必要があります。シェルの設定ファイルに次のように記述します(通常の$PATH:/opt/homebrew/bin/ではなく、/opt/homebrew/bin/:$PATHとします)

export PATH=/opt/homebrew/bin/:$PATH

fishの場合は次のようになります。

set PATH ~/.cargo/bin $PATH

問題2:プログラムをシェルから実行していない

ここまでの手順は、プログラムをシェルから実行する場合にのみ有効です。IDEやGUI、cronジョブなど、別の方法でプログラムを実行している場合は、PATHへの追加方法も異なります。詳しいやり方は状況によって変わります。

cronジョブの場合

いくつかの方法があります。

  • 実行するプログラムを/home/bork/bin/my-programのようにフルパスで指定する
  • crontabの1行目に、使いたいPATH全体を記述する(例:PATH=/bin:/usr/bin:/usr/local/bin:…)。シェルで使っているPATH全体はecho "PATH=$PATH"で確認できます。

IDEやGUIでの扱いについては、正直なところ長い間遭遇していないのでよくわかりません。詳しい方がいれば教えていただければ、ここに追記します。

問題3:PATHの重複でデバッグが難しくなる

PATHを編集してbash(またはzshfish)を実行して新しいシェルを起動すると、PATHに重複したエントリができてしまうことがよくあります。シェルを起動するたびに、設定がPATHへ追記されていくためです。

個人的には、この重複が原因で何かが壊れた経験はありません。ただ、PATHの中身を把握しようとしたときに、重複があるとデバッグが難しくなります。

対処法としては、次のようなものがあります。

  1. PATHをデバッグするときは、新しいターミナルを開いて「まっさらな」状態で行うようにします。そうすれば重複を避けられます。
  2. シェルの設定ファイルの末尾でPATHの重複を除去する(例えばzshではtypeset -U pathでできるようです)
  3. 追加する際に、そのディレクトリがすでにPATHに含まれていないか確認する(例えばfishではfish_add_path --path /some/directoryでできるはずです)

PATHの重複をどう解消するかはシェルによって異なり、組み込みの方法が常に用意されているわけではないので、使っているシェルでの方法を調べてみてください。

問題4:PATHを更新したら履歴が消えた

bashやzshで陥りがちな状況があります。

  1. コマンドを実行する(失敗します)
  2. PATHを更新する
  3. bashを実行して設定を再読み込みする
  4. 上矢印キーを何度か押して、失敗したコマンドを再実行しようとする(または新しいターミナルを開く)
  5. 失敗したコマンドが履歴にない!なぜでしょう?

これは、bashではデフォルトで、シェルを終了するまで履歴が保存されないために起こります。

修正方法としては、次のようなものがあります。

  • 設定を再読み込みするためにbashを実行する代わりに、source ~/.bashrc(zshならsource ~/.zshrc)を実行します。こうすると、現在のセッション内で設定が再読み込みされます。
  • シェルを終了したときだけでなく、常に履歴を保存するように設定します(方法はbashかzshかによって異なります。zshの履歴オプションは少し複雑で、どれが最善かは私もはっきりわかりません)

sourceについての補足

cargo(Rustのインストーラー)を初めてインストールすると、PATHの設定方法について次のような案内が表示されますが、そこでは具体的なディレクトリ名は一切出てきません。

This is usually done by running one of the following (note the leading DOT):

. "$HOME/.cargo/env"        	# For sh/bash/zsh/ash/dash/pdksh
source "$HOME/.cargo/env.fish"  # For fish

この行をシェルの設定ファイルに追加すると、スクリプトが自動的にPATH(やその他の設定)をセットアップしてくれるという仕組みです。

これはよくあるパターンで(例えばHomebrewでもbrew shellenvをevalすることを推奨しています)、対応方法は2つあります。

  1. ツールの提案通りにする(. "$HOME/.cargo/env"をシェルの設定ファイルに追加するなど)
  2. 実行するように言われたスクリプトがPATHにどのディレクトリを追加するのかを調べて、手動で追加する。私なら次のようにします。
    • シェルで. "$HOME/.cargo/env"を実行する(fishならfish用のバージョンを)
    • echo "$PATH" | tr ':' '\n' | grep cargoを実行して、どのディレクトリが追加されたか確認する
    • /Users/bork/.cargo/binと表示されたのを確認し、それを~/.cargo/binに短縮する
    • そのディレクトリ~/.cargo/binをPATHに追加する(この記事の手順で)

ツールの提案通りにすること自体はまったく問題ないと思います(むしろ「最善の方法」かもしれません!)。ただ個人的には、自分が何の設定を変更しているのかを正確に把握しておきたいので、たいていは2つ目の方法を使っています。

fish_add_pathについての補足

fishにはfish_add_pathという便利な関数があり、次のようにしてディレクトリをPATHに追加できます。

fish_add_path /some/directory

これはとても手軽でいいのですが(本当にシンプルなコマンドです!)、私は次のような理由で使うのをやめました。

  1. fish_add_pathを実行すると、将来のすべてのセッションでPATHが更新される場合(「ユニバーサル変数」として)と、現在のセッションだけで更新される場合があり、どちらになるのか判断が難しいことがあります。理論上はドキュメントに説明があるのですが、私には理解できませんでした。
  2. もし数週間後や数ヶ月後に、間違えたなどの理由でそのディレクトリをPATHから削除したくなった場合、削除するのが少し面倒です(ただし、このGitHub issueのコメント欄に手順は載っています)。

おわりに

この記事が誰かの役に立てば嬉しいです。PATHにディレクトリを追加する際にハマった大きな落とし穴が他にもあれば、あるいはこの記事について質問があれば、(MastodonやBlueskyで)ぜひ教えてください!

原文は Julia Evans により に公開されました。

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。