プログラミングを始めたばかりの頃、Python3をインストールするべく環境構築に取り組んでいました。
その際によく見かけたのは「パス($PATH
)を通す」という言葉です。当時の自分には何のことだか全く分からず「なんでプログラミングのインストールにバスケじゃあるまいし、パスが必要なんだろう...」と思ったものです。
今になっては、なぜパスを通す必要があるのか理解しているつもりです。
しかし、実際にどのように環境変数$PATH
が使われているのかまでは知りません。
何かしらのコマンドをインストールする際にどうしても流れ作業的に$PATH
を通しているので、あまり深く考えたことがありませんでした。
今回は環境変数$PATH
とは何なのか・どのように使われているのか深掘ってみたいと思います。
$PATHに登録されている値を見てみる
まずは実際に$PATH
にどのような値が格納されているのか見てみます。
先ほども書いたように$PATH
は環境変数であり、ターミナルから簡単に参照することが可能です。
$ echo $PATH /usr/local/bin:/System/Cryptexes/App/usr/bin: ...(省略)... /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/Library/Apple/usr/bin
$PATH
には複数の値が:
区切りで格納されています。
見やすさのために:
で区切って表示させてみると、思ったよりも多くの値が登録されていることに驚かされます。
/Users/xxxxxxxx/.rbenv/shims
/opt/homebrew/bin
/opt/homebrew/sbin
/usr/local/bin
/System/Cryptexes/App/usr/bin
:
/usr/bin
/bin
/usr/sbin
/sbin
/usr/local/go/bin
/Library/Apple/usr/bin
それぞれの値は何を示しているのでしょうか。
試しにfile
コマンドを使って/user/bin
が何なのか見てみるとディレクトリであることが分かりました。
他の値も同様にディレクトリだったので、環境変数$PATH
にはディレクトリのパスが:
区切りで格納されていることが分かりました。
$ file /usr/bin /usr/bin: directory
それぞれのディレクトリには何が入っているのか
ディレクトリへのパス情報ということは、該当のディレクトリは何かしらのファイルを含んでいるはずです。
一体、どのようなファイルが含まれているのでしょうか。先ほどと同じようにコマンドを使って確認してみます。
$ ls /usr/bin | head -n 5 AssetCacheLocatorUtil AssetCacheManagerUtil AssetCacheTetheratorUtil DeRez GetFileInfo
何やら見慣れないファイルが確認できました。
file
コマンドを使ってGetFileInfo
について、もう少し情報を確認してみます。
$ file /usr/bin/GetFileInfo /usr/bin/GetFileInfo: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e] /usr/bin/GetFileInfo (for architecture x86_64): Mach-O 64-bit executable x86_64 /usr/bin/GetFileInfo (for architecture arm64e): Mach-O 64-bit executable arm64e
...。
ガーッと情報が出力されていますが、要するにGetFileInfo
は実行可能なバイナリーフォマットのファイルであることを示しています。
なのでターミナルでGetFileInfo
と入力すれば、コマンドとして実行可能なはずです。
$ GetFileInfo usage: GetFileInfo [-P] [-a[<attrib-letter>] | -t | -c | -d | -m] <path> $ GetFileInfo index.ts file: "/Users/xxxxxxx/sample/index.ts" type: "\0\0\0\0" creator: "\0\0\0\0" attributes: avbstclinmedz created: 09/12/2023 22:05:19 modified: 09/12/2023 22:05:19
問題なく実行できました。
さらに先ほどの/usr/bin
ディレクトリには文字数の都合で省略しましたが、ちらほらと見慣れたファイル名も確認できました。
head
というファイル名があったので、おそらくhead
コマンドの実行ファイルだと考えられます。このコマンドをパスを指定して直接、呼び出してみるとどうなるでしょうか。
$ ls | /usr/bin/head -n 1 README.md
思った通りです。
つまり$PATH
に記録されている、それぞれのディレクトリには「実行可能なファイル」が入っていることが分かりました。
後付け的な紹介になりますが、先ほど$PATH
に格納されていた、いくつかのディレクトリには普段よく使うコマンドが含まれています。
- /bin: 一般的なコマンド格納先(cat、rmなど)
- /usr/bin: 一般ユーザ向けコマンド格納先(make、wgetなど)
- /usr/sbin: 管理者向けコマンド格納先(chroot、useraddなど)
- /usr/local/bin: 評価版パッケージや自作コマンドの格納先
Linuxコマンドのソースコードを取得する方法:オリジナルコマンド作成前の勉強向け #初心者 - Qiita
$PATHをいつ・どこで使っているのか
$PATH
について理解が深まりました。では実際に$PATH
はどこで、いつ使われているのでしょうか。
ターミナルにecho
と打ち込まれた後、コマンドが実行されるまでの流れを考えてみます。実際にターミナルの実装コードを見たわけではないので、あくまで推測です。
- ターミナルに打ち込まれた文字を解析する
- 解析結果より文字列
echo
を取得する - 環境変数
$PATH
を取得して:
区切りで分割してディレクトリの一覧を取得する - 各ディレクトリの中を順に検索し
echo
に該当する実行可能ファイルを検索する - 一致した実行可能ファイルを実行する
推測ではありますが、どこからでもecho
コマンドが使える仕組みは意外にもシンプルですね。
これが$PATH
たる一つの環境変数によって実現されていると思うと、その効力・パワフルさを感じさせられます。
今回のテーマから少し外れてしまいますが$PATH
に登録されている全てのディレクトリから該当のコマンドを探す際は、どのようなアルゴリズムが使われているのか気になります。登録されているディレクトリが多い場合など検索効率の悪化が起きそうなので、何かしらの工夫をしているはずです。
まとめ
今回は知っているようで知らない$PATH
について深掘ってみました。
$PATH
にはディレクトリへのパス情報が:
区切りで格納されている- それぞれのディレクトリは実行可能ファイルを含んでいる
- ターミナルがコマンドを参照する時、
$PATH
の値から該当のコマンドを検索する
自分自身、裏側で何が起きているのか・どういう使われ方をしているかをしっかりと把握できていなかったので、実行可能ファイルの存在を確認して直接、実行できた時はテンションが上がりました。
あらゆる箇所からコマンドが使えるのは$PATH
を使ったシンプルでパワフルな設計のおかげです。
少しでも「ええな〜」と思ったらはてなスター・はてなブックマーク・シェアを頂けると励みになります。