Pathを通すとは、環境変数とは


Pathを通すとか、環境変数を設定するとか、
なんとなくでしか理解してなかったのですが、明確に理解すると、
コマンドを円滑に使えることのありがたみを感じるようになったので、まとめてみました。

## 実行環境

- OS: MacOS v10.13
- Terminal: iTerms
- Shell: zsh

## Pathを通すとは

コマンドが格納されているPathを登録することです。
分かりにくいかもしれないので、詳しく記載します。

例えば、下記の2つは同じ動作をします。

```
$ pwd
$ /bin/pwd
```

これは、 `/bin` というPathが通されている時に成り立ちます。

`$ pwd` を実行することで、 `$ /bin/pwd` を実行するように設定する、
これが、**Pathを通す**と同義なのです。

極端に言えば、Pathなんて通さなくていいんです。
毎回、コマンドを打つ時は、

```
$ /bin/pwd
$ /bin/date
```

などのように打てばいいんです。
でも、面倒くさいですよね。w
スマートにコマンドを打てるようにするために、Pathを通しているのです。

### 通っているPathを確認

通っているPathは、echoコマンドで確認できます。

```
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```

`:` は区切りの意味。縦に並び替えてみます。

```
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
```

各Pathの中身を確認してみます。※本当はもっと長いので、...で一部省略。

```
$ ls /usr/local/bin
bin-proxy                         heroku                            sandbox-pod
brew                              htmldiff                          terminal-notifier
bundle                            httpclient                        tig
...

$ ls /usr/bin
2to3-                       httpdstat.d                 profiles
2to3-2.7                    ibtool                      prove
AssetCacheLocatorUtil       iconutil                    prove5.18
AssetCacheManagerUtil       iconv                       psed
AssetCacheTetheratorUtil    ictool                      psed5.18
BuildStrings                id                          pstopdf
CpMac                       idle                        pstruct
DeRez                       idle2.7                     pstruct5.18
GetFileInfo                 idlj                        ptar
...

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

$ ls /usr/sbin
AppleFileServer       disktool              newsyslog             slapconfig
BootCacheControl      diskutil              nfs4mapid             slapdn
DevToolsSecurity      distnoted             nlcontrol             slapindex
DirectoryService      dnctl                 notifyd               slappasswd
FileStatsAgent        dnsextd               ntpd                  slapschema
KernelEventAgent      dot_clean             ntpdate               slaptest
NetBootClientStatus   dsconfigad            ntpdc                 smbd
...

$ ls /sbin
apfs_hfs_convert fsck_hfs         kextunload       mount_exfat      newfs_apfs       quotacheck
autodiskmount    fsck_msdos       launchd          mount_fdesc      newfs_exfat      reboot
disklabel        fsck_udf         md5              mount_ftp        newfs_hfs        route
...
```

たくさん出てきました。**これら全てがコマンド**なんです。
知らないコマンドだらけで焦りますね。w

### Pathの設定・追加

exportコマンドを利用します。
Pathを `/xxx/bin` だけにしたい場合、

```
$ export PATH=/xxx/bin
```

とすれば、Pathは `/xxx/bin` だけに上書きされます。
Pathに `/xxx/bin` を追加したい場合は、

```
$ export PATH=/xxx/bin:$PATH
```

となります。間違えてPath追加しようと思って、
上を書いてしまったことがある方いるのではないでしょうか。

既に設定されているPathを全消しするケースはほぼないと思うので、
上記間違えないように気をつけましょう。

### Pathの取り消し

Pathを全消ししたい場合（ほぼないと思いますが）、

```
$ unset PATH
```

で消えます。

### Pathの優先順位

同じコマンドが2つ以上あった場合、
下記で一番左、今回であれば `/usr/local/bin` が優先されます。

```
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```

つまりたとえば、 `/usr/local/bin/hage` と `/bin/hage` が2つ存在する場合、
`$ hage` で実行されるのは `/usr/local/bin/hage` となります。

### コマンドの格納パスを探す

コマンドの格納パスは、whichコマンドで探すことができます。

```
$ which vi
/usr/bin/vi
```

## 環境変数とは

環境変数とは何なのか。一言で言うと、Terminal環境内における変数です。
往々にして、PCの環境についての変数です。

`printenv` というコマンドを打ってみます。
環境変数 `Environment Variable` をprintするという意味ですね。
※private情報なので、一部抜粋。

```
PWD=/Users/fuwamaki
SHELL=/bin/zsh
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
COLORTERM=truecolor
HOME=/Users/fuwamaki
USER=fuwamaki
LOGNAME=fuwamaki
ZSH=/Users/fuwamaki/.oh-my-zsh
PAGER=less
LESS=-R
LC_CTYPE=en_US.UTF-8
LSCOLORS=Gxfxcxdxbxegedabagacad
_=/usr/bin/printenv
```

PC環境内の変数一覧が表示されました。

- `USER` という環境変数のvalueが `fuwamaki`
- `PWD` という環境変数のvalueが `/Users/fuwamaki`

という意味です。

環境変数はPCそれぞれでデフォルトでいくつか定義されていますが、
もちろんカスタマイズすることもできます。

自分の場合、シェルとしてzshを利用しているので、
`SHELL=/bin/zsh` に設定しています。

### 環境変数とPath

上記に `PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin` 
という記載があります。
つまり、 **Pathは環境変数のうちの1つ** です。

<img src="https://i.imgur.com/OyoKGWC.png">

### 環境変数の設定

環境変数の設定はPath同様、exportコマンドを利用します。
環境変数`SAMPLE`に値`fuwa`を追加するには下記を実行します。

```
$ export SAMPLE="fuwa"
```

### 環境変数の更新

元々環境変数`SAMPLE="fuwa"`が設定されていたとします。その時、

```
$ export SAMPLE="fuwafuwa"
```

を実行すると、環境変数`SAMPLE`の値が`fuwafuwa`に更新されます。

### 環境変数を表示するexportコマンド

環境変数を表示するコマンドは `$ printenv` と先ほど記載しましたが、
`$ export -p` も環境変数を表示します。

`$ export -p` は厳密に言えば、exportで設定された環境変数です。
そのためシェル変数（後述）がある場合など、微妙に両者の結果は異なることがあります。


### 環境変数が消えてしまう？

環境変数を追加したのに、消えたことってないでしょうか？

exportで操作した環境変数は、設定したTerminalでだけにしか反映されません。
Terminalを再起動したり、別タブでTerminalを開いたりすると、
新しいTerminalの方には、exportで追加した環境変数はいません。

つまりexportコマンドは、exportするTerminalの環境変数を操作しているだけです。
PC自体の環境変数を操作しているわけではないのです。

### 永続的な環境変数を設定する

Terminalを立ち上げた時に、該当の環境変数が設定されていれば良いですよね。
Terminal立ち上げ時に実行されるファイルに、
exportで環境変数を追加する処理を加えれば良いです。

シェルの設定ファイル、今回の場合であれば`.zshrc`に処理を加えます。
`.zshrc`はターミナル立ち上げ時に必ず読み込まれます。
bashを利用している方は、`bash_profile`や`.bashrc`が相当します。

下記を`.zshrc`ファイルの中に追加で記載します。

```
export SAMPLE="fuwa"
```

`.zshrc`ファイルが読み込まれないといけないので、
Terminalを再起動します。

または、再起動せずにsourceコマンドで`.zshrc`を読み込んでも良いです。

```
$ source ~/.zshrc
```

Terminal立ち上げ時に上記のexport行が必ず読み込まれるので、
永続的な環境変数を設定できたことになります。

## シェル変数

環境変数と似たようなもので、シェル変数というものがあります。
シェル変数とは、現在実行中のシェルだけで有効な変数です。

### シェル変数の追加

exportのような、シェル変数を操作する用のコマンドはありません。
シェル変数`SAMPLE`に値`fuwa`を追加するには下記を実行します。

```
$ SAMPLE="fuwa"
```

シェル変数が追加されたかどうかを確認しましょう。
echoコマンドを利用します。

```
$ echo $SAMPLE
fuwa
```

`$`を必ずつけてください。これでシェル変数の追加ができました。

### シェル変数を環境変数にする

シェル変数SAMPLEを事前に設定しておけば、

```
$ export SAMPLE
```

とすれば、SAMPLEは環境変数になります。

### シェル変数と環境変数の違い

- シェル変数： 現在実行中のシェルだけで有効な変数
- 環境変数: シェルから実行したコマンドにも引き継がれる変数

です。これを具体的に説明するには、
親プロセスと子プロセスの説明が必要なので、詳しくは別記事にします。

## コマンドまとめ

今回特に紹介したかったコマンドを下記にまとめます。

```
$ printenv #環境変数の一覧を表示
$ export -p #exportした変数の一覧を表示
$ echo [message] #messageの内容表示
$ echo $[環境変数] #環境変数のvalueを表示
$ which [コマンド] #コマンドの格納パスを表示

$ export [環境変数]=[value] #環境変数にvalueを設定
$ [シェル変数]=[value] #シェル変数にvalueを設定
$ export [シェル変数] #シェル変数を環境変数に設定
$ unset [変数] #変数の設定を取り消し

$ source [ファイル] #ファイルを読み込む
```