PATHを通すってどういうこと？コマンドはどこにある？

## 概要
コマンドをなんともなしにうちこんではいるけど、コマンドってどこのあるんだろうか。
PATHを通すってよく聞くけど、どういうことなんだろうか。
そんなことを思った初心者に向けて書いた記事です。
コマンドのコードを読むとかはしないです。

ちなみに各コマンドはMacとzshにて試してますが、Unix系なら似たようなものです。

## 結論
先に結論を言ってしまうと、PATHを通すとは、**外部コマンドの場所をコマンドサーチパスに登録し、外部コマンドをパスで指定せずとも実行できるようにすること**です。
詳細は下記に記します。


## 内部コマンドと外部コマンド

コマンドには以下のように、シェルに組み込まれている**内部コマンド(ビルトインコマンド)**と、特定のディレクトリ配下にファイルとして置かれている**外部コマンド**があります。


![パッケージ管理マネージャ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32691/8d0ebdcd-dc4f-140a-94d9-a60c2c72044f.png)



## lsコマンドはどこにある？

ためしに `ls`コマンドの場所を `which` コマンドで見てみましょう。

```
$ which ls
```

出力:

```
/bin/ls
```

どうやら `/bin` 直下にあるようです。

## /bin の中には何がある？

では次に`/bin`の中を見てみましょう。

```
$ ls /bin
```

出力:

```
[		chmod		dash		df		expr		ksh		ln		mv		pwd		sh		sync		unlink
bash		cp		date		echo		hostname	launchctl	ls		pax		rm		sleep		tcsh		wait4path
cat		csh		dd		ed		kill		link		mkdir		ps		rmdir		stty		test		zsh
```

よく使うコマンドと同じ名前のファイルがありますね。


## 外部コマンドの実体はファイルです

試しに`ls`コマンドの中身を見てみると、**バイナリファイル**であることがわかります。

```
$ od -h /bin/ls | more
```

**出力:**

```
0000000      facf    feed    0007    0100    0003    0000    0002    0000
0000020      0013    0000    0710    0000    0085    0020    0000    0000
0000040      0019    0000    0048    0000    5f5f    4150    4547    455a
0000060      4f52    0000    0000    0000    0000    0000    0000    0000
(略)
```


## 外部コマンドを実行するには
内部コマンドは、コンピュータ起動時にメモリに読み込まれていますが、**外部コマンドは、ディスクにファイルとして存在し(`/bin`配下など)、毎回ディスクから読み込まれる**ようになっています。

つまり、外部コマンドを実行する際は、**直接パスを指定して外部コマンドを実行できます**。

**例: 直接ファイルの置き場所を指定してlsコマンドを実行**

```bash

$ /bin/ls
```

上記のようにすればコマンドを実行できますが、それでは面倒なので `PATH`という環境変数が用意されています。
これは厳密には**コマンドサーチパス(コマンド検索パス)**と呼ばれるものです。

直接パスを指定しなくても、プログラムが勝手にコマンドサーチパスを見てコマンドを検索するため、以下のように `ls`コマンドが実行できるわけです。

```bash

$ ls
```


## PATHの中身は、外部コマンドを有するディレクトリ群

`PATH`の中身をいったん見るために `echo` コマンドで `PATH`を見てみます。

```zsh

$ echo $PATH
```


**出力:**

```
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin
```

結果をみるといくつかのディレクトリが`:`で区切られて出力されました。

```
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
/Library/Apple/usr/bin
```

これらが外部コマンドの置き場所(パス)を示しています。



## PATHが通っていないと

`PATH`が通っていなかったり、存在しないコマンドを実行しようとすると以下のようになります。

**例: zshの場合**

```
zsh: command not found: hogehoge
```

該当のコマンドを既に入れたはずなのに、`not found` などと言われる場合、
`PATH` が通ってないことが多いです。

## PATHを通すには

`PATH` を通すためにやることは、**環境変数`PATH`に、使いたいコマンドが置いてあるディレクトリのパスを追記する必要があります。**

例えば、`/hogehoge/bin` 配下にある`php`コマンドを使いたい場合、
`/hogehoge/bin`を環境変数`PATH`に追加します。

試しに`export`コマンドを用いて追加してみます。

```shell
$ export PATH="/hogehoge/bin:$PATH"
```

`echo` で追加されているかどうか確認。(追加されたコマンドをうってみてもOK)

```shell
$ echo $PATH
```
**出力:**

```shell
/hogehoge/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin
```

上記のように、環境変数には`export`コマンドを用いて追加できますが、いちいち`export`コマンドを使って追加するのは面倒なので、基本的に**使用しているシェルの設定ファイルに追記します。**

こうすることでシェルを起動する際に、自動的に`PATH`が上書きされるようになります。

**例: zshの場合** 

HOMEディレクトリ配下の`.zshrc`ファイルにて `export`を用いて追記します。


```zsh:.zshrc
export PATH="/hogehoge/bin:$PATH"
```

最後 `$PATH`と書いていますが、これは既存の環境変数`PATH`を展開しています。つまり、以下と同じ意味です。

```zsh:.zshrc
export PATH="/hogehoge/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
```

このときに、既存のものを完全に上書きしてしまうと、**いろいろなコマンドが使えなくなってしまうので注意。**
例えば、以下のようにしてしまうと、**/bin 配下などのコマンドが読み込まれなくなります。**

```zsh:.zshrc
export PATH="/hogehoge/bin"
```

以上のように、環境変数`PATH`を用いると、所定の外部コマンドを直接パスを指定せずに実行することができるようになります。
シェルの設定ファイルに関してわからない方は、自分の使っているシェルを調べて、書き方をググって見るとよいです。


## PATHの優先順位

`PATH`には優先順位があります。
例えば以下の場合だと、左の`/hogehoge/bin`から順番に読み込まれるようになっています。

```
PATH=/hogehoge/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin
```

例えば、`/hogehoge/bin`と、`/use/local/bin`にそれぞれ`php`というコマンドがあった場合、

```
$ php
```

と実行した場合に読み込まれるのは、`/hogehoge/bin`の`php`コマンドになるということです。

このように、`PATH`を指定する際は、優先順位にも気をつける必要があります。


## 各コマンドの置き場所( /bin や /usr/local/bin など)の違い

外部コマンドの置き場所は、FHS（Filesystem Hierarchy Standard）で**「こういうコマンドはこの場所に置きましょうね！」**という形で標準化されています。
これにより、どのLinux系のシステムをいじっても、「この`/bin`ってディレクトリには緊急時でも使えるコアなコマンドが置いてあるんだな」と一目瞭然になるわけです。
(ただし、標準化されているとはいえ、強制しているわけではないので、各OSごとで変なコマンドが変な場所にあったりすることも)

これらで標準化されている外部コマンドの置き場所、それぞれの違いを以下の表にまとめてみましたが、一個ずつ見ていきます。

| ディレクトリ   | シングルユーザモード | ひとこと概要  |
|----------------|----------------------|------------|----------------|
| /bin           | 利用可             | 緊急時でも使えるやつ | 
| /usr/bin       | 利用不可            | 一般的なやつ |
| /usr/local/bin | 利用不可            | 自作のスクリプトとか  |   
| /sbin          | 利用可            |  スーパーユーザー（root）特権が必要 |   
| /usr/sbin      | 利用不可           | スーパーユーザー（root）特権が必要  |

### /bin
シングルユーザモードでも使える**一番コアな外部コマンド**をこのディレクトリ配下に置きます。
シングルユーザモードとは、OSが正常に起動できないときなどの非常時に利用するものです。

最初でも確認したとおり、筆者のMacbookProの`/bin`には以下のコマンドが入っていましたね。

```
[		chmod		dash		df		expr		ksh		ln		mv		pwd		sh		sync		unlink
bash		cp		date		echo		hostname	launchctl	ls		pax		rm		sleep		tcsh		wait4path
cat		csh		dd		ed		kill		link		mkdir		ps		rmdir		stty		test		zsh
```
これらのコマンドについて知らない人は、調べてもらえれば、どれもシンプルかつ重要なコマンドであることがわかります。

### /usr/bin
シングルユーザモードで使わず、基本的にパッケージマネージャ(パッケージ管理システム)に管理されるコマンドを置きます。
パッケージマネージャは各OSごとにいろいろなものがありますが、ここでは触れません。
実際どんなコマンドがあるかは、自分のマシンのディレクトリを覗いて確認してみましょう。

### /usr/local/bin
シングルユーザモードで使わず、パッケージマネージャに管理されないコマンドを置きます。

ちなみに、Macユーザーおなじみのパッケージマネージャであるhomebrewですが、
このディレクトリを使います。
なぜhomebrewがこの場所を使うかは、homebrewのページに書いてあります。

https://docs.brew.sh/FAQ#why-does-homebrew-prefer-i-install-to-usrlocal

翻訳すると、以下のように言っています。
>Appleはこのディレクトリを非システムユーティリティ用に割り当てています。つまり、デフォルトでは /usr/local にはファイルが存在しないので、既存のツールやシステムツールを台無しにする心配はありません。


### /sbin や /usr/sbin
基本的に上記の各階層のディレクトリと同じ扱いですが、`bin`とは違い、システム管理者がいじるような管理用のコマンドを置きます。
これらはスーパーユーザー(root)権限が必要になるため、一般ユーザーでは使用できません。



## まとめ
結論は先にも書いたとおり、
> PATHを通すとは、外部コマンドの場所をコマンドサーチパスに登録し、外部コマンドをパスで指定せずとも実行できるようにすること

ということでした。

PATHを通すついでに、内部コマンドと外部コマンドにも言及している記事があまり見当たらなかったので、今回書いてみました。