インタラクティブシェルとログインシェルからbash_profileとbashrcの違いを理解する

#はじめに
こんにちは、いっきゅうです。
twitter:[@ikk_hck](https://twitter.com/ikk_hck)

たまには人の役に立ちそうな記事をかいてみようということで、すでに擦られた内容ではありますが、できるだけわかりやすくまとめてみようと思います。
先に答えだけ知りたい方は下の方の本題から読んでください。

#前提
そもそもシェルとひとくちにいっても色いろなタイプがあります。
ここでいうタイプとはbashやzshなどではなく”モード”のことです。
インタラクティブかどうか、またログインシェルかどうかの組み合わせの2x2で、４つのタイプがあります。
<ul>
<li>インタラクティブなログインシェル</li>
<li>インタラクティブなノンログインシェル</li>
<li>ノンインタラクティブなノンログインシェル</li>
<li>ノンインタラクティブなログインシェル</li>
</ul>

これらを理解するためにはさらにログインシェルとインタラクティブシェルを理解する必要があります。

###ログインシェル
sshでマシンにログインしたときなどに起動されるシェルです。後に触れますが、GUIでログインしてターミナルを立ち上げた場合もログインシェルが起動します。
　一方、ログインシェルからさらに新しくbashを起動すると、それはノンログインシェルとして起動されます。bashを起動する際に
 
```Bash
$ bash --login
```
のように--loginをつけると新しく起動する場合でもログインシェルになります。

####ログインシェルとノンログインシェルの見分け方
<ul><li>ログインシェルの場合</li></ul>

```Bash
$ echo $0
-bash
```
ログインシェルの場合bashという文字列にハイフンがつきます。
もしくは

```Bash
$ shopt login_shell
login_shell    	on
```
login_shellがonになっています。
<br>

<ul><li>ノンログインシェルの場合</li></ul>

```Bash
$ echo $0
bash
```
bashという文字列の前にハイフンがつきません。
もしくは

```Bash
$ shopt login_shell
login_shell    	off
```
login_shellがoffになっています。
<br>


###インタラクティブシェル
インタラクティブなシェルはttyのユーザ入力からコマンドを受け取り実行します。つまりユーザの入力に対して出力をします。
　一方ノンインタラクティブなシェルとは、たとえばシェルスクリプトを実行する際に使用されるシェルのことです。このシェルはユーザ入力を受け取りません。
<br>

####インタラクティブシェルかどうかの見分け方
<ul><li>インタラクティブシェルの場合</li></ul>

```Bash
$ echo $-
himBH
```
出力は"himBH"となります。

<ul><li>ノンインタラクティブシェルの場合</li></ul>

```Bash
$ bash -c 'echo $-'
hBc
```
ノンインタラクティブシェルで'echo $-'実行するコマンドです。
-cは、渡される文字列をコマンドとして認識して実行するというオプションです。
上記のコマンドで起動されるシェルは、渡されたコマンドを実行するためだけに起動されるのでノンインタラクティブです。また出力は"hBc"となります。

###４つのタイプ
以下具体例をあげてそれぞれのタイプに触れていきます。

<ul>
<li>インタラクティブなログインシェル</li>
たとえばGUIでログインし、アプリケーションなどからterminalを開いたりしますが、あれです。あるいはsshでログインした場合などは自動的にインタラクティブなログインシェルが起動されます。

<li>インタラクティブなノンログインシェル</li>
ノンログインシェルとは、ログインシェルから"$bash"などと入力して起動したシェルのことです。

<li>ノンインタラクティブなノンログインシェル</li>
シェルスクリプトを実行する際に起動される。シェルスクリプトは独自のサブシェルで実行され、このシェルは対話型ではありません。スクリプトを実行するためだけに開かれ、スクリプトが終了するとすぐに閉じます。

<li>ノンインタラクティブなログインシェル</li>
このシェルの説明をあえて最後に持ってきたのは使う機会が稀だからです。たとえば以下のようにsshで自身に接続し（ログインシェルが起動）、実行したいコマンドを流し込めば（非対話型）非対話的なログインシェルの挙動が確認できます。
shoptコマンドについては後に触れます。
</ul>

```Bash
$ echo 'echo $-; shopt login_shell' | ssh localhost
Pseudo-terminal will not be allocated because stdin is not a terminal.
Password:
hB
login_shell    	on
```

以上の４つのタイプのシェルそれぞれでインタラクティブかどうか、またログインシェルかどうかをためしてみると、たしかにそうなっていることがわかると思います。

#本題
いよいよ本題のbash_profileとbashrcの違いについて触れていきたいと思います。
下の図を見てください。今までの内容がわかれば下のフローチャートも理解できると思います。~~めんどくさいので~~すごくわかりやすい図なので他のサイトの図を引用させていただきました。

![Screen Shot 2021-05-02 at 18.11.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197716/25a21127-c474-9a0a-4522-657538fdc535.png)

（図の引用元：https://blog1.mammb.com/entry/2019/12/01/090000 ）

基本的にはターミナルを操作するときはログインシェルをインタラクティブに利用することが多いかと思います。したがってよく耳にする「まずbash_profileが読み込まれてbashrcがよみこまれる」ということになるわけですね。
　また、ノンログインシェルをインタラクティブに使用する際はbash_profileは読み込まれずbashrcが読み込まれます。したがってスクリプトを実行するときに反映させたいシェルの設定をbash_profileに書いていても反映されないわけです。

##bash_profile
端的に言えば、bash_profileの特徴をいくつかあげると
<ul>
<li>ログイン時にのみ1回実行される</li>
<li>環境変数はプロセス間で引き継がれるのでbash_profileに記述する</li>
<li>bash_profile内にbashrcを読み込むための記述を書き込むことが多い</li>
</ul>
です。よく

```Bash
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
```
のような記述でbashrcを読み込む記述がされています。

##bashrc
bashrcの特徴をいくつがあげると
<ul><li>bashが起動されるたびによみこまれる</li>
<li>エイリアスやshell変数を記述</li></ul>
などがあげられると思います。
<br>
<br>
<br>

では。