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だ。
どのファイルをシステムが使っているかわからない場合は、次のようにテストするのがおすすめだ:
~/.bashrcにecho hi thereと追記する- ターミナルを再起動する
- 「hi there」と表示されれば、
~/.bashrcが使われているということだ!やった! - 表示されなければ、その行を削除して
~/.bash_profileで同じことを試す - 最初の2つでうまくいかなければ、
~/.profileでも試してみよう。
(bashがどの設定ファイルを使うかを説明する精巧なフローチャートは世の中にたくさんあるが、正直それらを覚える価値はないし、実際に試してみるのが一番早くて確実だ)
ステップ3: 追加すべきディレクトリを特定する
例えばhttp-serverというプログラムをインストールして実行しようとして、うまくいかないとする。こんな感じだ:
$ npm install -g http-server
$ http-server
bash: http-server: command not foundhttp-serverがどのディレクトリにあるか、どうやって見つければいいだろうか? 正直、これは一般的にはそう簡単ではない。たいてい答えは「npmがどう設定されているかによる」といったものになる。いくつかヒントを挙げておこう:
- 新しいインストーラー(
cargoやnpm、homebrewなど)を初めてセットアップする際、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/を付ける)
- Node/npm:
ステップ3.1: 本当に正しいディレクトリか確認する
正しそうなディレクトリを見つけたら、本当に合っているか確認しよう! 例えば、自分のマシンではhttp-serverは~/.npm-global/binにあることがわかった。そのディレクトリで次のようにhttp-serverを直接実行してみれば、正しいか確認できる:
$ ~/.npm-global/bin/http-server
Starting up http-server, serving ./publicうまくいった! PATHに追加すべきディレクトリがわかったので、次のステップに進もう!
ステップ4: シェルの設定ファイルを編集する
これで必要な2つの重要な情報が揃った:
- PATHに追加したいディレクトリ(例:
~/.npm-global/bin/) - シェルの設定ファイルの場所(例:
~/.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つある:
- 新しいターミナル(またはターミナルのタブ)を開く。混乱しないように古い方は閉じておくといい
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/:$PATHfishなら:
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(やzsh、fish)を実行して新しいシェルを起動すると、PATHに重複したエントリができてしまうことがよくある。シェルを起動するたびにPATHに新しいものが追加されていくからだ。
個人的には、この種の重複で何かが壊れた経験はないが、PATHの中身を理解しようとする際に、重複があるとデバッグが難しくなることがある。
対処法としては次のようなものがある:
- PATHをデバッグするなら、新しいターミナルを開いてそこで行う。そうすれば「まっさらな」状態で確認でき、重複を避けられる。
- シェルの設定ファイルの末尾でPATHを重複排除する(例えばzshでは
typeset -U pathでできるらしい) - 追加する際にすでにPATHに含まれていないか確認する(例えばfishでは
fish_add_path --path /some/directoryでできるはず)
PATHの重複をどう排除するかはシェルによって異なり、組み込みの方法が常に用意されているわけではないので、使っているシェルでのやり方を調べてみる必要がある。
問題4: PATHを更新したあとに履歴が消える
bashやzshで陥りがちな状況がある:
- コマンドを実行する(失敗する)
- PATHを更新する
bashを実行して設定を再読み込みする- 上矢印を何回か押して失敗したコマンドを再実行しようとする(または新しいターミナルを開く)
- 失敗したコマンドが履歴にない! なぜ?
これは、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つある:
- ツールが推奨するとおりにする(例えば
. "$HOME/.cargo/env"をシェルの設定ファイルに追加する) - 実行するように言われたスクリプトが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つの理由から使うのをやめた:
- fish_add_pathは、将来のすべてのセッションでPATHを更新する(「ユニバーサル変数」として)場合と、現在のセッションだけでPATHを更新する場合があり、どちらになるのか自分には判断が難しい。理論上はドキュメントに説明があるのだが、自分には理解できなかった。
- もし数週間や数ヶ月後に間違いに気づいてPATHからそのディレクトリを削除したくなった場合、それが結構難しい(ただし、このGitHub issueのコメント欄にやり方が書かれている)。
おわりに
この記事が誰かの役に立てば嬉しい。PATHにディレクトリを追加する際にハマった大きな落とし穴が他にもあれば、あるいはこの記事について質問があれば、(MastodonやBlueskyで)ぜひ教えてほしい!
記事をランダムに読む
コメント
ログインしてコメントする