環境構築をすることが多くなり、PATHを通す機会が増えました。
今までは書いてある通りのコードを意味も理解せず追加してPATHを通していましたが、そのコードの意味をちゃんと理解して、PATHを通すとは何をしているのかを知りたいと思い調べました。
この記事のゴール
PATHを通すとどうなるのか理解する。
通したPATHを読めるようになる。
(今回はnodenvを使用する際に通すPATH export PATH="$HOME/.nodenv/bin:$PATH"
の意味を理解したいと思います)
1.PATHを通すとどうなるのか
そもそもパスとは何か
「PATHを通す」を理解する前に、そもそもパスとは何かを調べます。
パス(path)とは…
コンピュータ内で特定の資源の所在を表す文字列のことをパスという。
ストレージ(外部記憶装置)内でファイルやディレクトリ(フォルダ)の位置を表すのに用いられるが、他の用途でも使われる。
パスとは - IT用語辞典 e-Words より
特定のディレクトリの場所を示す、道順のようなものです。
ex:Desktopのパス
/Users/mac(※ユーザ名)/Desktop
メモ知識:pathは日本語で「経路」という意味を持つ
環境変数のPATH
「PATHを通すとどうなるか」を知るには、環境変数の1つであるPATH
の理解が重要になります。
環境変数とはなにか、というところから調べてみます。
環境変数とは
OSが提供する機能の1つです。
環境変数とは、OSが設定値などを永続的に保存し、利用者や実行されるプログラムから設定・参照できるようにしたもの。プログラムの実行時などに必要となる、利用者やコンピュータごとに内容が異なる設定値などを記録するために用いられる。
環境変数とは - IT用語辞典 e-Words より
環境変数は以下のコマンドで確認できます。
$ printenv
出力結果
mac$ printenv
TERM_PROGRAM=iTerm.app
SHELL=/bin/bash
TERM=xterm-256color
USER=mac
...省略
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
...省略
HOME=/Users/mac
LOGNAME=mac
SECURITYSESSIONID=186a8
_=/usr/bin/printenv
TERM_PROGRAM
、SHELL
、TERM
といったワードが全て環境変数と呼ばれるものです。
それぞれの変数に対して値が入っています。
TERM_PROGRAM=iTerm.app
SHELL=/bin/bash
環境変数一覧の中に**PATH
**があることが確認できます。
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
値は/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
ですが、:
は区切りの意味なので、区切りで改行すると以下の値が入っていることが分かります。
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# 区切り:で改行
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
メモ知識:シェルやターミナル上で環境変数を使用するときは、**環境変数の前に$
**をつけることで使用できる。
# 環境変数PATHの内容を表示する
$echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
環境変数PATHの役割
PATHは環境変数の1つであり、/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
といった値が入っていることが分かりました。(通しているPATHによって値は異なります)
では、この環境変数PATHに値を入れることで何が起こるのでしょうか?
PATHは、コマンド実行ファイルが保存されているディレクトリの場所を設定する変数で、PATHに登録されたディレクトリにあるコマンドは、コマンド名のみで実行できるようになります。
メモ知識:コマンド … シェルなどが解釈して実行する、システムへの指示
ターミナルでコマンド実行ファイルのパスを入力すると、コマンドを実行します。
例えば、printenvコマンドは/usr/bin/printenvと入力することで実行できます。
$which printenv
/usr/bin/printenv
# printenvコマンドは/usr/binの中にあるため/usr/bin/printenvで実行できる。
$/usr/bin/printenv
TERM_PROGRAM=iTerm.app
SHELL=/bin/bash
TERM=xterm-256color
・・・省略
しかし、$printenv
のみでも同じ出力結果を得られます
$printenv
TERM_PROGRAM=iTerm.app
SHELL=/bin/bash
TERM=xterm-256color
・・・省略
なぜ/usr/bin/printenv
と書かずにprintenv
だけでも実行できるのでしょうか?
それは、**環境変数PATHに/usr/bin
がある(=パスが通っている)**からなんです。
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# 区切り:で改行
/usr/local/bin
/usr/bin
# ↑これ
/bin
/usr/sbin
/sbin
シェルはコマンドがパスの指定なし(/usr/bin/printenvではなくprintenv
)で入力された時、環境変数PATHに設定してあるディレクトリへコマンド実行ファイルを探しに行き、同じ名前のファイルがあればそれを実行します。
正確には、パスなしでコマンドを実行する際、シェルは「エイリアス」→「ビルトインコマンド」→「環境変数PATHに登録されているディレクトリにある実行コマンド」
の順番で探し、最初に見つけたものを実行します。
・PATHを理解して、コマンドの在りかを探してみよう
$printenv
を実行した時の流れ
# 1. printenvコマンドを実行
$printenv
# 2. エイリアス、ビルトインコマンドを確認。該当するコマンドがない場合は環境変数PATHを確認します。
# 3. 環境PATHを確認
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# 先頭に記述されているディレクトリから順番にそのディレクトリ下にprintenvの実行ファイルがあるかを確認していきます
/usr/local/bin
↓
/usr/bin
↓
/bin
↓
/usr/sbin
↓
/sbin
# 4. /usr/local/binの下にprintenvの実行ファイルがあるか確認します。存在しない場合は、次に記述されているディレクトリを確認します
/usr/local/bin # printenvの実行ファイルなし
↓
/usr/bin
# 5. /usr/binの下にprintenvの実行ファイルがあるか確認し、printenvコマンドが存在することを確認
/usr/binにprintenvの実行ファイルがある!
# 6. /usr/binの下にあるprintenv実行ファイルが実行されます
/usr/bin/printenvの実行
# 出力結果
TERM_PROGRAM=iTerm.app
SHELL=/bin/bash
TERM=xterm-256color
・・・省略
このような流れにより、コマンド実行ファイルが入っているディレクトリのパスを環境変数PATHに追加する(=PATHを通す)ことで、コマンド名だけで実行できるようになるのです。
まとめ
PATHを通すとどうなるのか
PATHを通したディレクトリ内にあるコマンド実行ファイルを、コマンド名のみで実行できるようになる。逆に、PATHを通さないとコマンド名のみでは実行できない。
寄り道① PATHが通ってない時のエラー
PATHが通っていないのにコマンド名のみで実行すると、command not found
といわれます。このエラーがでたときはPATHがちゃんと通っているか確認してみましょう。
#nodenvコマンドがあるディレクトリのPATHを通さずに$nodenvを実行してみる
#ファイルパスを指定して実行
$/Users/mac/.nodenv/bin/nodenv -v
nodenv 1.3.1+11.5024679
#コマンド名のみで実行
$nodenv -v
-bash: nodenv: command not found
#PATHが通っていないためコマンドを見つけられない
寄り道② /usr/binにあるコマンド実行ファイルをみてみる
/usr/bin
ディレクトリには、printenv
コマンドの他にもたくさんのコマンド実行ファイルが入っています。
どんなコマンドが入っているのでしょうか?ターミナル上で確認してみようと思います。
# /usr/binの中身を表示
$ls /usr/bin
2to3-@ machine*
2to3-2.7@ mail*
AssetCacheLocatorUtil* mailq@
AssetCacheManagerUtil* mailx*
AssetCacheTetheratorUtil* make*
BuildStrings* makeinfo*
CpMac* malloc_history*
DeRez* man*
...省略
みたことのないコマンドがたくさんあります。/usr/binのPATHは通っているので、ここにあるコマンドはコマンド名だけで実行することができます。
/usr/binの他にも、今PATHが通っているディレクトリの中身を確認するのも面白いと思います。
2.通したPATHを読む
PATHを通すとどうなるか理解できたところで、実際にPATHを通すコードを読んでみたいと思います。
PATHの通し方については詳しく説明しないので、知りたい方は以下の記事をぜひ参考にしてみてください。
・MacでPATHを通す
今回はnodenvのPATHを通すコードを読んでいきます
export PATH="$HOME/.nodenv/bin:$PATH"
nodenvの環境構築は以下の記事を参考にして行いました。
・nodenv を使って Mac に Node.js の環境を構築する
ではexport
から読んでいきます。
export 〜
で環境変数を変更します。
メモ知識:export … 環境変数やシェル変数を設定するコマンド
PATH=〜
でPATH変数に値を代入しています。
代入する値は"$HOME/.nodenv/bin:$PATH"
です。
シェルは$環境変数
を使用すると、環境変数を展開することができます。
# 環境変数HOMEの値を確認
$echo $HOME
/Users/mac
# 環境変数PATHの値を確認
$echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# bash_prifileに export PATH="$HOME/.nodenv/bin:$PATH" を追加
#.bash_profileの更新
$source ~/.bash_profile
# 環境変数PATHの確認
$echo $PATH
PATH=/Users/mac/.nodenv/bin/nodenv:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
$HOME と $PATH が展開されている!!
詳しく内容を読み解いていきます。
$HOME/.nodenv/bin:$PATH
の$HOME
は**/Users/mac**、$PATH
は**/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin**になっています。
そのため、$HOME/.nodenv/bin
は**/Users/mac/.nodenv/bin/nodenv**となります。
:
で区切りを表し、そのあとに$PATH
がきているので、/Users/mac/.nodenv/bin/nodenv + 区切り : + PATHの値**/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin**になります。
よって環境変数PATHの値には、もとのPATHに**/Users/mac/.nodenv/bin/nodenv**が追加されたものが代入されることになります。
# PATHの値
PATH=/Users/mac/.nodenv/bin/nodenv:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# 区切り:で改行
/Users/mac/.nodenv/bin/nodenv
# ↑追加されている
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
まとめ
nodenvで通したPATHを読む
export PATH="$HOME/.nodenv/bin:$PATH"
このコードは、PATH変数の値の前に$HOME/.nodenv/bin:
を追加し、その値をPATH変数に代入する、という意味である。
寄り道① 代入する値を書く時の注意
代入する値を''(シングルクォーテーション)
で囲むと変数の展開がされない
#ダブルクォーテーション
# export PATH="$HOME/.nodenv/bin:$PATH"
$echo $PATH
PATH=/Users/mac/.nodenv/bin/nodenv:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
#なし
# export PATH=$HOME/.nodenv/bin:$PATH
$echo $PATH
PATH=/Users/mac/.nodenv/bin/nodenv:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
#シングルクォーテーション
# export PATH=’$HOME/.nodenv/bin:$PATH’
$echo $PATH
$HOME/.nodenv/bin:$PATH
# ↑ 環境変数の展開がされていない
寄り道② $PATH:$HOME/.nodenv/bin
export PATH="$PATH:$HOME/.nodenv/bin"
という書き方も見たことがありますが、これはPATHの値の後ろに:$HOME/.nodenv/bin
を追加し、その値をPATHに代入する、という意味になります。PATHを通すコードの読み方が理解できたので違いが分かりますね。
PATHを通す、ということについて自分なりに調べてみました。「とりあえずやっていたこと」が何をしていたのか理解できると、変更を加える時やエラーが起きた時に対応できるようになるなーと思いました。
#参考