How to add a directory to your PATH

Julia Evans

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

原文は Julia Evans により に公開されました。 このブログを購読する

今日、友人と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を使っていることがわかる。たぶんすでに自分でわかっているとは思うが)

ちなみにbashはLinuxで、zshはMac OSでデフォルトになっている(2024年時点)。この記事では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にあることがわかった。そのディレクトリで次のようにhttp-serverを直接実行してみれば、正しいか確認できる:

$ ~/.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の最初の行に使いたい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(やその他の設定)をセットアップしてくれるという考え方だ。

これはかなり一般的で(例えばHomebrewbrew 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

これはイケてる(なんてシンプルなコマンド!)のだが、自分は2つの理由から使うのをやめた:

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

おわりに

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

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

コメント