LoginSignup
5
6

More than 1 year has passed since last update.

今日こそ『パスが通らない!!』から完全におさらばするための記事

Last updated at Posted at 2023-02-05

はじめに

環境構築で必ずぶちあたる壁の1つが「パスが通らない」ことです。Command not foundとシェルに怒られるたびに、そこらへんに転がってる記事に書いてある内容を意味もわからずにそのまま実行してる人も多いんじゃないでしょうか。

この記事を読んで、今日こそ『パスが通らない!!』から完全におさらばしましょう!

環境変数

記事に書いてあるexport PATH=/foo/bar:$PATHを意味もわからずに実行してませんか?まずはこの式の意味を理解しましょう。

環境変数とは

環境変数とは、OSが保持するKey-Value型のデータのことです。OSが保持しているので、異なるプロセス間で同じデータを共有することができます。

操作

まずは軽く環境変数を操作してみて、環境変数について理解を深めましょう。

作成

試しに~という値を持つ環境変数exampleを作成してみます。

$ export example=~

以下はどちらも同じ出力結果になります。

$ echo ~
$ echo $example

環境変数の名前を大文字にするか小文字にするかですが、以下の記事が参考になります。今回の例では小文字を使う方が適切なようです。

慣習的には、他のアプリケーションやユーザーに設定させて引き継ぐことを意図する環境変数には大文字を使い、それ以外には小文字を使うことが多いようです。

大文字でない環境変数を利用することに問題はありますか - スタック・オーバーフロー

表示

以下のようにして、指定した環境変数に設定されている値を表示できます。

$ echo $example

ちなみに以下のように実行すると、環境変数の一覧が表示されます。

$ export -p

...

declare -x example="/home/ubuntu"

...

上書き

再度値を設定すると、元の値を上書きできます。

$ export example=Hello
$ echo $example
Hello

以下のように元の値を残しつつ、デリミタ(区切り文字)を使って文字列を追加することもできます。環境変数においては、:(コロン)がデリミタになります。

$ export example=$example:World
$ echo $example
Hello:World
$ export example=x:$example
$ echo $example
x:Hello:World

つまり、export PATH=/foo/bar:$PATHというのは、既存の環境変数PATHの値の先頭に/foo/bar:という文字列を追加するという意味になります。環境変数PATH自体については後述します。

ちなみに下記のように、間にダブルクオーテーションを2つ挟めば、デリミタを使わずに文字列を追加できます。

$ export example=$example""!
$ echo $example
x:Hello:world!

削除

下記のようにして環境変数を削除できます。

$ unset example
$ echo $example

$PATHとは?

お次に$PATHについて理解しましょう。$PATHは環境変数の1つだということは前述したとおりですが、どのように使われるものなのでしょうか?

コマンド検索パス

結論から言うと、$PATHの値はコマンド検索パスになります。コマンド検索パスとは、シェルがコマンドの実行ファイルを探しに行くパスのことです。この説明だけだとよくわからないですね。もう少し詳しく説明します。

Linuxコマンドの1つにlsコマンドがあると思います。試しにlsコマンドを実行してみましょう。カレントディレクトリにあるファイルの一覧が表示されると思います。

$ ls

次に、以下のように実行してみてください。環境によってwhich lsの実行結果が違ってくるとは思いますが、適宜読み替えてください。

$ which ls
/bin/ls

whichは指定したコマンドの実行ファイルのパスを表示してくれるコマンドです。lsというコマンドの実行ファイル(プログラム)が/bin/lsという場所にあることがわかります。試しにls /binと実行してみてください。lsというファイルが存在することがわかると思います(他にも見覚えのある名前がいくつかあるでしょう)。

つまり、今までコマンドとして実行していたlsは、シェルによって/bin/lsと読み替えられて実行されていたのです(その証拠に/bin/lsと実行するとlsと同じ実行結果が得られます)。ではなぜシェルはls = /bin/lsと解釈することができたのでしょうか?

その答えがコマンド検索パスになります。$PATHの持つ値を見てみましょう。

$ echo $PATH
...:/bin...

見づらいですが、複数のパスが:で区切られて表示されており(前述しました)、その中に:binがあると思います。

つまり、lsが実行されると、シェルはまずカレントディレクトリ内にlsという実行ファイルが存在するかを確認し、なければ$PATHの持つ値(コマンド検索パス)を確認して、それらのパスが指し示す場所にlsという実行ファイルが存在するかを1つずつ確認していきます。今回の場合は、/binの下にlsが存在するので、シェルは/bin/lsを実行するわけです。

ちなみに、$PATHの値が...:/usr/bin:/bin...となっていて、/usr/binの下にもlsが存在する場合は、シェルは/usr/bin/lsを実行します。先に書いてあるパスが優先して使われるわけです。

「パスが通らない」とは

つまり、「パスが通らない」とは、シェルに実行ファイルまでのパスを渡せてないということです。もっと詳しくいうと、$PATHに実行ファイルが存在するディレクトリのパスが書かれていないということになります。

なので「パスを通す」には、$PATHに実行ファイルが存在するのパスを追記してあげればいいわけです。追記するのは先頭と後ろのどちらでもいいとは思いますが、万が一同じ名前の実行ファイルがあった場合のために先頭に追記してあげることが多いです。

$ export PATH=/foo/bar:$PATH

設定ファイル

さてこれでパスを通せるようになるぞと思った人もいるかもしれませんが、export PATH=/foo/bar:$PATHを実行してパスを追加するだけでは不十分です。

というのも、シェルでexport PATH=/foo/bar:$PATHを実行して環境変数の値を設定しても、その設定が持続するのはそのセッションの間だけで、シェルを閉じてしまうと、設定した内容が全て消えてしまいます。

恒久的にその設定を適用し続けるには、シェルでexport PATH=/foo/bar:$PATHを実行するのではなく、シェルの設定ファイルにexport PATH=/foo/bar:$PATHを書き込む必要があります。

シェルごとの設定ファイルの種類

シェルには、bash、zsh、shなどがあります。それぞれのシェルごとに使用する設定ファイルが異なりますので、それぞれの使用する設定ファイルについて詳しく見ていきましょう。

bash

デフォルトのシェルをbashにしている場合は、以下の設定ファイルが順番に読み込まれます。全て実態はシェルスクリプトなので、単なる設定だけでなく、処理なども記述することができます。

  1. /etc/profile
  2. ~/.bash_profile
  3. ~/.bash_login
  4. ~/.profile
  5. ~/.bashrc
  6. ~/.bash_logout

/etc/profile

全ユーザーに適用されるデフォルトの設定ファイルです。ユーザー単位では編集する必要はないので、ほとんどいじることはないと思います。ログイン時に全ユーザーに適用したい設定や処理がある場合に使います。

~/.bash_profile

あればログイン時に読み込まれます。無くても問題ありません。ユーザー単位の設定を記述します。ログイン時に一度だけ読み込めばいい設定や処理のみを記述し、余計なものは極力書かない方がいいようです。

環境変数はプロセス間で受け継がれるので、ログイン時のみ読み込めればOKなため、環境変数を記述するのによく使われます。なので、「パスを通す」ためには、このファイルにexport PATH=/foo/bar:$PATHを追記することで、恒久的にパスを通すことができるようになります。

~/.bash_login

~/.bash_profileが存在しない場合にのみ、あればログイン時に読み込まれます。無くても問題ありません。

~/.profile

~/.bash_profile~/.bash_loginの両方が存在しない場合にのみ、あればログイン時に読み込まれます。無くても問題ありません。

特定のシェルに依存しない設定ファイルなので、bashに依存しない環境変数や、GUIで使う設定を書くのに使われます。

~/.bashrc

あれば対話モードのbashを起動するときに読み込まれます。無くても問題ありません。

環境変数でない変数や、エイリアス、シェル関数、コマンドライン補完の設定、シェルオプション、プロンプト設定、EDITOR変数などのbashに依存する対話モード向けの設定や処理を書くのに使います。

逆に言うと、対話モードのbashを使用するときにのみ適用されるので、環境変数をここに書くのは適切ではありません(GUIや対話モードのbash以外から起動するプログラムなどに環境変数が渡らなくなるため)。

また、rsyncなどのsshパイプで問題が生じることがあるため、~/.bashrcに、標準出力や標準エラーに何かが出力されるような処理を書いてはいけないらしいです。

~/.bash_logout

あればログアウト時に読み込まれます。無くても問題ありません。

zsh

途中

sh

途中

設定ファイルにexport PATH=/foo/bar:$PATHを追記する

bash

前述したように、bashで実行するコマンドのパスを通したいときは、~/.bash_profileに、GUIやbash以外から起動するプログラムにて使用する場合は~/.profileに、export PATH=/foo/bar:$PATHを追記しましょう。

ただ、環境によって読み込まれる設定ファイルの順番などが異なる場合があります。一番確実なのは、~/.bashrcと、~/.profile~/.bash_profile~/.bash_loginの3つのうちで存在するファイル全てに対して環境変数を記述することです(3つ全て存在しない場合は~/.profileに記述してください)。

pyenvのドキュメントに記述されている内容を根拠にしています。ご指摘等ある方はこの記事のコメント欄にて教えていただけると幸いです。

Stock Bash startup files vary widely between distributions in which of them source which, under what circumstances, in what order and what additional configuration they perform. As such, the most reliable way to get Pyenv in all environments is to append Pyenv configuration commands to both .bashrc (for interactive shells) and the profile file that Bash would use (for login shells).

Then, if you have ~/.profile, ~/.bash_profile or ~/.bash_login, add the commands there as well. If you have none of these, add them to ~/.profile.

pyenv - GitHub

例えば、~/.bash_loginが存在しない場合は、~/.bashrc~/.profile~/.bash_profileに環境変数を記述します。

$ echo "export PATH=/foo/bar:$PATH" >> ~/.bashrc
$ echo "export PATH=/foo/bar:$PATH" >> ~/.bash_profile
$ echo "export PATH=/foo/bar:$PATH" >> ~/.profile

ちなみにパスは絶対パスで指定する必要があります。

zsh

途中

sh

途中

設定ファイルの変更を適用させる

設定ファイルを変更したら、以下のコマンドを実行しないと変更が反映されません。

$ source <設定ファイルのパス>

または、以下のコマンドでも反映できます。複数のファイルを編集した場合は、上記のコマンドだとファイル数分実行しないといけないので、下記のコマンドの方が楽です。

$ exec $SHELL

その他参考文献

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6