Linuxサーバログイン時の/etc/bashrc、/etc/profile、~/.bashrc、~/.bash_profile等の読み込み順序が気になったので調べてみた

[「LinuCレベル1」の試験](https://linuc.org/linuc1/range/)勉強をしていると、bashの設定ファイルの読み込み順序について、以下のような表で説明されていました。

|  | 全員が参照 | ユーザー個別で参照 |
|:-|:-|:-|
|ログイン時に読み込み|/etc/profile|1. ~/.bash_profile<br>2. ~/.bash_login<br>3. ~/.profile|
|bash起動時に読み込み|Debian系: /etc/bash.bashrc<br>RedHat系: /etc/bashrc|~/.bashrc|

この読み込み順序のルールについてはなんとなく知ってはいたんですが。。。

- `/etc/profile` と `~/.bash_profile` はどちらが先に読み込まれるの？
- ホームディレクトリ配下で `~/.bash_login` というファイルは見たことがないけど、このファイルの読み込み順序はどうなってるの？
- RedHat系とDebian系で違いはあるの？

といった点が気になってしまったので、実際に検証してみました。

---

### 今回の動作確認環境
- Vagrant 2.2.14 
- CentOS 8
- Ubuntu21.10 (Impish Indri)

---

### CentOS8の場合

RedHat系OSの検証環境としてCentOS8を利用します。

まず、既存の各設定ファイルの開始行に「ファイル名:start」、最終行に「ファイル名:end」と出力されるように追記してみました。

```
$ sudo sed -i '1i echo "/etc/profile:start"' /etc/profile
$ sudo sed -i '$a echo "/etc/profile:end"' /etc/profile
$ sudo sed -i '1i echo "/etc/bashrc:start"' /etc/bashrc 
$ sudo sed -i '$a echo "/etc/bashrc:end"' /etc/bashrc
$ sed -i '1i echo "~/.bash_profile:start"' ~/.bash_profile 
$ sed -i '$a echo "~/.bash_profile:end"' ~/.bash_profile 
$ sed -i '1i echo "~/.bashrc:start"' ~/.bashrc 
$ sed -i '$a echo "~/.bashrc:end"' ~/.bashrc 
```

上記の修正を行った状態でログインしてみると、以下のように表示されました。

```
$ bash --login
/etc/profile:start
/etc/bashrc:start
/etc/bashrc:end
/etc/profile:end
~/.bash_profile:start
~/.bashrc:start
/etc/bashrc:start
/etc/bashrc:end
~/.bashrc:end
~/.bash_profile:end
```

`start` 〜 `end` の入れ子状態の表示結果から

- `/etc/profile` の中で `/etc/bashrc` を読み込んでいる。
- `~/.bash_profile` の中で `~/.bashrc` を読み込んでいる。
- `~/.bashrc` の中で `/etc/bashrc` を読み込んでいる。

という仮説が立てられます。

順にファイルの中身を見ていきましょう。
まずは `/etc/profile` ですが、以下のように `/etc/bashrc` が読み込まれていました。

```:/etc/profile
if [ -n "${BASH_VERSION-}" ] ; then
        if [ -f /etc/bashrc ] ; then
                # Bash login shells run only /etc/profile
                # Bash non-login shells run only /etc/bashrc
                # Check for double sourcing is done in /etc/bashrc.
                . /etc/bashrc
       fi
fi
```

`~/.bash_profile` では以下の箇所で `~/.bashrc` が読み込まれていました。

```:~/.bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
```

`~/.bashrc` は以下の箇所で `/etc/bashrc` が読み込まれていました。

```:~/.bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi
```

調査の結果、読み込み順序としてはこのようになりました。

1. /etc/profile
1. /etc/bashrc
1. ~/.bash_profile
1. ~/.bashrc
1. /etc/bashrc

---

前述の表では「ログイン時に読み込み」と「ユーザー個別で参照」の箇所に `~/.bash_login` と `~/.profile` が記載されていますが、CentOSの一般ユーザーのホームディレクトリ配下にこれらのファイルは存在しません。
`man bash` を見てみると、 `INVOCATION` つまり各設定ファイルの「呼び出し」に関する箇所に、以下のような記載を見つけました。
説明によると `~/.bash_profile` 、 `~/.bash_login` 、 `~/.profile` の順に検索して最初に見つかったファイルを読み込んで実行するようです。

```
INVOCATION
       〜省略〜
       When bash is invoked as an interactive login shell, or as a  non-interactive
       shell with the --login option, it first reads and executes commands from the
       file /etc/profile, if that file exists.  After reading that file,  it  looks
       for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads
       and executes commands from the first one that exists and is  readable.   The
       --noprofile  option  may  be  used when the shell is started to inhibit this
       behavior.
```

`man bash` に書かれていた内容を検証するために `~/.bash_profile` を以下のようにリネームし、擬似的に `~/.bash_profile` を未存在の状態にして、 `~/.bash_login` を作成します。

```
$ mv ~/.bash_profile ~/.bash_profile.backup
$ echo 'echo "~/.bash_login:start"' > ~/.bash_login
$ echo 'echo "~/.bash_login:end"' >> ~/.bash_login
```

上記の対応を行った状態でログインしてみると、以下のように `~/.bash_login` が読み込まれました。

```
$ bash --login
/etc/profile:start
/etc/bashrc:start
/etc/bashrc:end
/etc/profile:end
~/.bash_login:start
~/.bash_login:end
```

`~/.bash_profile` が存在しない状態での読み込み順序はこのような結果になりました。

1. /etc/profile
1. /etc/bashrc
1. ~/.bash_login

---

次に `~/.bash_login` を以下のようにリネームし、擬似的に `~/.bash_login` を未存在の状態にして、 `~/.profile` を作成します。

```
$ mv ~/.bash_login ~/.bash_login.backup
$ echo 'echo "~/.profile:start"' > ~/.profile
$ echo 'echo "~/.profile:end"' >> ~/.profile
```

上記の対応を行った状態でログインしてみると、以下のように `~/.profile` が読み込まれました。

```
$ bash --login
/etc/profile:start
/etc/bashrc:start
/etc/bashrc:end
/etc/profile:end
~/.profile:start
~/.profile:end
```

`~/.bash_profile` 、 `~/.bash_login` が存在しない状態での読み込み順序はこのような結果になりました。

1. /etc/profile
1. /etc/bashrc
1. ~/.profile

これらの結果から `~/.bash_profile` が存在しない場合は、一般ユーザーのbash起動時の設定である `~/.bashrc` はログイン時に自動的に読み込まれないようなので、 `~/.bash_profile` と同様の動きにするには `~/.bash_login` 、 `~/.profile` の中で以下のように `~/.bashrc` を読み込む記述が必要であることがわかりました。

```
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi
```

---

ここまではログイン時の動作を検証しましたが、bash起動時の動作も確認しておきましょう。
bashを起動してみると、以下のような表示になりました。

```
$ bash
~/.bashrc:start
/etc/bashrc:start
/etc/bashrc:end
~/.bashrc:end
```

ログイン時に読み込まれるファイル群が登場しないので当然と言えば当然ですが、読み込み順序としてはこのような結果です。

1. ~/.bashrc
1. /etc/bashrc

---

### Ubuntu21.10 (Impish Indri)の場合

Debian系OSの検証環境としてUbuntu21.10を利用します。

CentOS8の場合と同様に、既存の各設定ファイルの開始行と最終行を以下のように修正します。

```
$ sudo sed -i '1i echo "/etc/profile:start"' /etc/profile
$ sudo sed -i '$a echo "/etc/profile:end"' /etc/profile
$ sudo sed -i '1i echo "/etc/bash.bashrc:start"' /etc/bash.bashrc
$ sudo sed -i '$a echo "/etc/bash.bashrc:end"' /etc/bash.bashrc
$ sed -i '1i echo "~/.bashrc:start"' ~/.bashrc 
$ sed -i '$a echo "~/.bashrc:end"' ~/.bashrc
$ sed -i '1i echo "~/.profile:start"' ~/.profile 
$ sed -i '$a echo "~/.profilee:end"' ~/.profile 
```

上記の修正を行った状態でログインしてみると、以下のように表示されました。

```
$ bash --login
/etc/profile:start
/etc/bash.bashrc:start
/etc/bash.bashrc:end
/etc/profile:end
~/.profile:start
~/.bashrc:start
~/.bashrc:end
~/.profilee:end
```

CentOS8と比較すると `/etc/bashrc` 、 `~/.bash_profile` が存在せず、その代わりに `/etc/bash.bashrc` 、 `~/.profile` が存在します。そういったファイル名の違いはありますが、読み込み順序としてはだいたい同じ結果となりました。

1. /etc/profile
1. /etc/bash.bashrc
1. ~/.profile
1. ~/.bashrc

---

CentOS8の場合と同じように、 `~/.profile` を以下のようにリネームし、擬似的に `~/.profile` を未存在の状態にして、 `~/.bash_profile` を作成してみます。

```
$ mv ~/.profile ~/.profile.backup
$ echo 'echo "~/.bash_profile:start"' > ~/.bash_profile
$ echo 'echo "~/.bash_profile:end"' >> ~/.bash_profile
```

上記の対応を行った状態でログインしてみると、以下のように `~/.bash_profile` が読み込まれました。

```
$ bash --login
/etc/profile:start
/etc/bash.bashrc:start
/etc/bash.bashrc:end
/etc/profile:end
~/.bash_profile:start
~/.bash_profile:end
```

`~/.profile` が存在しない状態での読み込み順序はこのような結果になりました。

1. /etc/profile
1. /etc/bash.bashrc
1. ~/.bash_profile

---

次に `~/.bash_profile` を以下のようにリネームし、擬似的に `~/.bash_profile` を未存在の状態にして、 `~/.bash_login` を作成します。

```
$ mv ~/.bash_profile ~/.bash_profile.backup
$ echo 'echo "~/.bash_login:start"' > ~/.bash_login
$ echo 'echo "~/.bash_login:end"' >> ~/.bash_login
```

上記の対応を行った状態でログインしてみると、以下のように `~/.bash_login` が読み込まれました。

```
$ bash --login
/etc/profile:start
/etc/bash.bashrc:start
/etc/bash.bashrc:end
/etc/profile:end
~/.bash_login:start
~/.bash_login:end
```

`~/.profile` 、 `~/.bash_profile` が存在しない状態での読み込み順序はこのような結果になりました。

1. /etc/profile
1. /etc/bash.bashrc
1. ~/.bash_login

---

Ubuntuの場合でも、bash起動時の動作を確認しておきましょう。
bashを起動してみると、以下のような表示になりました。

```
$ bash
/etc/bash.bashrc:start
/etc/bash.bashrc:end
~/.bashrc:start
~/.bashrc:end
```

ログイン時では `/etc/bash.bashrc` は `/etc/profile` から読み込まれる形になっていましたが、bash起動時にはいずれかのファイルから読み込まれるという形式ではなく `~/.bashrc` よりも先に単体で読み込まれるという結果になりました。

1. /etc/bash.bashrc
1. ~/.bashrc

---

### まとめ

ここまでの検証結果を元に各ファイルの読み込み順序を表にまとめてみました。

|  | CentOS8 | Ubuntu21.10 (Impish Indri) |
|:-|:-|:-|
|ログイン時の読み込み順序|1. /etc/profile<br>2. /etc/bashrc<br>3. ~/.bash_profile( or ~/.bash_login or ~/.profile)<br>4. ~/.bashrc<br>5. /etc/bashrc|1. /etc/profile<br>2. /etc/bash.bashrc<br>3. ~/.profile( or ~/.bash_profile or ~/.bash_login)<br>4. ~/.bashrc|
|bash起動時の読み込み順序|1. ~/.bashrc<br>2. /etc/bashrc|1. /etc/bash.bashrc<br>2. ~/.bashrc|

CentOSとUbuntuでは標準で存在するファイル名自体に違いがあることは知っていましたが、CentOSの場合は、 `/etc/bashrc` は `~/.bashrc` を経由して読み込まれるけど、 Ubuntuの場合は、 `/etc/bash.bashrc` は `~/.bashrc` を経由せずに読み込まれるといった違いに気づくことができました。
普段何気なくログインしている環境も、こういったところに着目してみると新たな発見があって面白いですね。

### 参考URL
- [本当に正しい .bashrc と .bash_profile の使ひ分け](https://qiita.com/magicant/items/d3bb7ea1192e63fba850)
- [.bash_profileと.bashrcなんて使い分けなくてよかったんや！](https://qiita.com/dark-space/items/cf25001f89c41341a9fd)
- [.bash_profile ? .bashrc ? いろいろあるけどこいつらなにもの？](https://qiita.com/hirokishirai/items/5a529c8395c4b336bf31)
- [.bash_profileと.bashrcについて](https://qiita.com/shyamahira/items/260862743e4c9794b5d2)
- [.bash_profileと.bashrcのまとめ](https://qiita.com/takutoki/items/021b804b9957fe65e093)
- [bashの設定ファイル（.bash_profile, .bashrc等）がどんなときに読み込まれるかまとめ](https://qiita.com/aosho235/items/3c2e123ab346eb568826)
- [Linuxで環境変数が保存される仕組み(bash_profile)](https://qiita.com/tomo0/items/674e06da84c921f5407a)
- [ログインシェルとインタラクティブシェルと~/.bashrc達の関係](https://qiita.com/incep/items/7e5760de0c2c748296aa)
- [.bash_profileや.bashrcをフラグメントする(.bash.d)](https://qiita.com/NewGyu/items/e3a5b3e2224f96b68fcc)
- [Ubuntu14.04で.bash_profileが読み込まれない（見つからない）](https://qiita.com/y_minowa/items/f6198afaf43d68de61c6)
- [インタラクティブシェルとログインシェルからbash_profileとbashrcの違いを理解する](https://qiita.com/ikkyu193/items/5c9a87b22fdf7697422e)
- [シェルの設定ファイル(bash)](https://qiita.com/saikoro-steak/items/2e9b177fea202186bd2c)
- [【投稿】bashが起動時〜bashrcとbash_profileについて〜　自分メモ用](https://qiita.com/ginokinh/items/45ac4cd16f766a426532)
- [shとbashを区別してbashのときだけ~/.bash_profileを読ませる~/.profileの書き方](https://qiita.com/h12o/items/9f2306071b0d6b6b9cb1)
- [Ubuntuで色がなくなる理由と改善策](https://qiita.com/upnt/items/022c5fc916d8a289e326)
- [bash_profileとかって誰が読んでいるんだろうと。](https://qiita.com/a_a_s/items/6975f26a45fef9c832cf)
- [bash / .bash_profile / .bashrcについて「とりあえず」部分を理解する](https://qiita.com/nzzzz/items/132968ec9ee226efa8eb)
- [Homesteadで.bash_profileをいじったらターミナルの文字が白くなった](https://qiita.com/yyykms123/items/2c991a18a6892f516d91)
- [WSLのデフォルトシェルが真っ白になった話(.bashrcと.bash_profile)](https://qiita.com/Minato_seagull/items/a27263f1432e58f5518d)
- [.bashrcの変更が保存されない時,そもそも.bashrcがない時](https://qiita.com/reoisym/items/eb2df532b3b0d11c8a1b)
- [シェルスクリプトでbashrcが読み込めない](https://qiita.com/takaram/items/17e739e9b7d4d7b6de42)
- [.bashrcと.bash_profileのどちらが先に読み込まれる？の罠](https://qiita.com/mollinaca/items/b99d04226d8b3b6e4fe0)
- [bashrcとbash_profile](https://qiita.com/OTAGRAMER/items/bbdcc8cc8e7bae7fbe02)
- [bash_profileとbashrcの違いについて](https://qiita.com/kh250/items/5b754e10c68e065cea95)
- [.bash_profileと.bashrcの使い方](https://qiita.com/takuyanagai0213/items/91f9c3c0287442367b34)
- [.bashrcと.bash_profileの違い](https://qiita.com/Aseiide/items/c917a7b59b135949e2b8)
- [.bash_profileとか.bash_loginとか.profileとか.bashrcとか.bash_logoutとか多すぎる](https://rdera.hatenadiary.org/entry/20080806/p1)
- [Bash: .bashrcと.bash_profileの違いを今度こそ理解する](https://techracho.bpsinc.jp/hachi8833/2021_07_08/66396)
- [bash の初期化ファイル .profile, .bashrc, .bash_profile の使い分けと管理方針](https://blog1.mammb.com/entry/2019/12/01/090000)
- [bashの.profileや.bashrc等を実行する動作仕様](https://blog.sgry.jp/entry/2019/11/09/232927)