0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Bashの設定ファイルはなぜこんなに多い?読み込み順について調べたこと

0
Last updated at Posted at 2026-09-27

bashをログインシェルとしたとき、複数の設定ファイルを順番に読み込むことを知ったが、いまいち納得できなかった
なぜ複数あり、なぜその順番になっているのか?
結論:「誰が・どういう目的でbashを起動したのか」によって読み込む設定を変えるため

「全ユーザー共通の設定」「ユーザー個人の設定」「ログイン時だけの設定」「対話操作時だけの設定」を分離

読み込み順序は、

共通設定 → 個人設定 → より具体的な設定

という「上書きできる仕組み」になっている

そもそもbashとは

ユーザーがOSに命令を伝えるための「シェル(shell)」の一種
英語の shell(殻) という名前がわかりやすい。コンピュータと人間の間に入る
コンピューターの中心を、Linux ・Kernel と考えるとカーネルがCPU、メモリ、ディスク、ネットワークなどを管理している

┌─────────────────────┐
│       Linux         │
│      Kernel         │
└─────────────────────┘

人間が直接カーネルに 「このファイルを表示して!」 「このプロセスを終了して!」と命令しようとするととても面倒なことになる
そこで、その外側に人間が操作しやすいインターフェースを置くことができる

        あなた
          ↓
      ┌───────┐
      │ Bash  │ ← Shell
      └───────┘
          ↓
   ┌─────────────┐
   │ Linux Kernel│
   └─────────────┘

つまり、「人間の命令を受け取り、それをLinux上で実行するための通訳兼操作環境」のこと

bashには「種類」がある

A. ログインシェル

SSHで、ログインした場合に

ssh opc@サーバー

コマンドが実行されると

「ユーザーがLinuxにログインして、作業を始める」

というbashができる
SSH接続するたびに、そのログインセッション用のBashが起動される


B. 非ログインシェル

ログインした後、

bash

と入力した場合などに起動する

何かにログインしているわけではない


C. 対話型シェル

人間とリアルタイムに対話しながら入力を受け付けるシェル

$ ls
$ cd /var/log
$ pwd

こういうコマンドを入力すると応じたプログラムを起動してくれる


D. 非対話型シェル

人間がコマンドを入力しない形式のシェル
スクリプトを実行するときなどは対話型ではない

./backup.sh

このようなファイルのスクリプトを実行するときは非対話型シェルが起動している


上記の分類でいうと、bashの種類についてはログイン/非ログイン と 対話型/非対話型 という2つの軸で考えると整理しやすい

            bash
                 │
      ┌───────┴─────────┐
       ログイン       非ログイン
  ┌─────┴─────┐  ┌─────┴─────┐ 
  対話型   非対話型 対話型    非対話型
     └── SSHなど

状況に適した設定ファイルが必要

ひとつの設定ファイルにすべて記載すると、コンピュータのリソースを無駄にしてしまうため、使い分けが必要になる

設定ファイルの例

ファイル 主な役割
/etc/profile 全ユーザー共通のログイン設定
~/.bash_profile そのユーザーのログイン設定
~/.bashrc そのユーザーの対話型bash設定
/etc/bashrc システム全体の対話型bash設定

例えば設定ファイルを

~/.bashrc

に絞り、下記の設定を入力する

export PATH=...
alias ll='ls -la'
echo "Welcome!"

この状態だと、
スクリプトを実行しただけなのにログイン用の処理が実行される
SSHログインしたときだけ必要な設定を、単なるbash起動でも実行してしまう
といった問題が起きる
そこでbashは、起動条件ごとに設定ファイルを分けることで、不要な初期化処理を適用しない構成にできる

「ログインシェル」の場合

Bashをログインシェルとして起動した場合、典型的には、

/etc/profile
    ↓
~/.bash_profile
    ↓
~/.bashrc

の順に読み込まれる

Bashのログインシェルはまず、

/etc/profile

を読み、その後、

~/.bash_profile

→ なければ ~/.bash_login
→ それもなければ ~/.profile

という探索をする

ログインシェルが読む順番(Oracle Linux 9の場合)

ファイル 主な役割
1 /etc/profile 全ユーザー共通のログイン設定
2 ~/.bash_profile そのユーザーのログイン設定
3 ~/.bashrc そのユーザーの対話型bash設定
4 /etc/bashrc システム全体の対話型bash設定

標準とはまた違う可能性があるらしいので、正確には下記を参照
参照:
https://www.gnu.org/software/bash/manual/bash.pdf?utm_source=chatgpt.com

なぜ /etc/profile が最初なのか

システム全体の設定を先に適用するため

例えばユーザー100人を管理している管理者が、

PATH=/usr/local/bin:/usr/bin:/bin

のような環境を全ユーザーの設定ファイルに書くのは面倒だから

/etc/profile

には共通設定を書く!

~/.bash_profileとは?

/etc/profileにあるユーザー共通の設定を上書きできる(イメージの)ファイル
さらに正確に表現するならユーザー固有の初期化処理のためのファイル

例えば管理者が、ユーザー共通として下記を設定したとする

PATH=/usr/local/bin:/usr/bin:/bin

一般ユーザー共通の設定は上記のままにして、~/.bash_profileに下記を設定すれば、自分だけ違う設定にできる

PATH=/home/admin/bin:/usr/local/bin:/usr/bin:/bin
/etc/profile

で全員共通の初期設定をして、
その後、

~/.bash_profile

で個人設定を必要な部分だけ上書きしたような状態にできる

後から実行された設定が、現在の設定を変更できる

例えば、
/etc/profile :

EDITOR=vi

~/.bash_profile :

EDITOR=vim

の場合、最終的な環境は

EDITOR=vim

になる

ファイル 主な役割 パラメータ
1 /etc/profile 全ユーザー共通のログイン設定 EDITOR=vi
2 ~/.bash_profile そのユーザーのログイン設定 EDITOR=vim
3 ~/.bashrc そのユーザーの対話型bash設定 書けるけど書かない
4 /etc/bashrc システム全体の対話型bash設定 書けるけど書かない
/etc/profile
    ↓
EDITOR=vi

~/.bash_profile
    ↓
EDITOR=vim

最終結果
    ↓
EDITOR=vim

.bashrc について

.bashrc は通常、 対話型bashのための設定を書く場所

「人間がコマンドを打つとき便利にする設定」

例:

alias ll='ls -lah'
alias ..='cd ..'
PS1='\u@\h:\w\$ '

Red Hat系の環境では ~/.bash_profile の中に下記のように記載し、自動で続けて読み込むように設定していることが多い

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

読み込む順番

ファイル 主な役割
1 /etc/profile 全ユーザー共通のログイン設定
2 ~/.bash_profile そのユーザーのログイン設定
3 ~/.bashrc そのユーザーの対話型bash設定
4 /etc/bashrc システム全体の対話型bash設定

整理すると

分類 システム全体 そのユーザーだけ
/etc/ ~/
ログイン関係 profile /etc/profile ~/.bash_profile
対話操作関係 bashrc /etc/bashrc ~/.bashrc

Unix/Linuxの設計思想

Linuxの設定はログイン時の環境設定に限らず 共通設定をまず読み、その後で個人が必要な部分を変更する
また、個別に必要な「上書き」をするために「順番」を決めている

各設定ファイルについて暗記をするより、下記の原則がどう適用されるかを覚えておく方が便利
-bashは、自分がどういう状況で起動されたかによって読む設定を変える
-大きな範囲⇔小さな範囲について設定されたファイルを読み込む
-システム全体⇔各機能
-全ユーザー共通⇔個別ユーザー

ログインシェルの場合:

/etc/profile :全ユーザー共通のログイン環境
       ↓
~/.bash_profile :ユーザー個別のログイン環境
       ↓
~/.bashrc :ユーザー個別の対話操作用の設定

課題

先述の設計思想によると、~/.bash_profileよりも先に/etc/bashrcの方が読まれないといけないはず
-大きな範囲→小さな範囲の順に設定ファイルを読み込む
-全ユーザー共通→個別ユーザー
ではなぜ、/etc/bashrcが例外になっているのか?

/etc/profile はBash専用のファイルではなく、伝統的にログイン時の共通環境設定に使われるファイルで、シェルによって読み込まれ方が異なる
などの理由がありそうだが、はっきりしたことはわからずこの記事では解決できなかった。今回の時点では例外として覚えておく

                 bash
                  │
        ┌─────────┴─────────┐
        │                   │
    login shell        non-login shell
        │                   │
   /etc/profile             │
        │                   │
 ~/.bash_profile            │
        │                   │
   ~/.bashrc  ←─────────────┘
        │
        ▼
   対話環境完成

付録

下記コマンドで現環境を調査した
詳しく読み込んで理解したいが、それも後に譲ることにする

cat /etc/os-release
echo "$SHELL"
ps -p $$ -o pid,ppid,args
cat /etc/profile
cat ~/.bash_profile
cat ~/.bashrc
cat /etc/bashrc
[opc@ホスト名 ~]$ cat /etc/os-release
NAME="Oracle Linux Server"
VERSION="9.7"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="9.7"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Oracle Linux Server 9.7"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:9:7:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://github.com/oracle/oracle-linux"

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 9"
ORACLE_BUGZILLA_PRODUCT_VERSION=9.7
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=9.7
[opc@ホスト名 ~]$
[opc@ホスト名 ~]$ echo "$SHELL"
/bin/bash
[opc@ホスト名 ~]$
[opc@ホスト名 ~]$ ps -p $$ -o pid,ppid,args
    PID    PPID COMMAND
  46629   46628 -bash
[opc@ホスト名 ~]$
[opc@ホスト名 ~]$ cat /etc/profile
# /etc/profile

# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

pathmunge () {
    case ":${PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                PATH=$PATH:$1
            else
                PATH=$1:$PATH
            fi
    esac
}


if [ -x /usr/bin/id ]; then
    if [ -z "$EUID" ]; then
        # ksh workaround
        EUID=`/usr/bin/id -u`
        UID=`/usr/bin/id -ru`
    fi
    USER="`/usr/bin/id -un`"
    LOGNAME=$USER
    MAIL="/var/spool/mail/$USER"
fi

# Path manipulation
if [ "$EUID" = "0" ]; then
    pathmunge /usr/sbin
    pathmunge /usr/local/sbin
else
    pathmunge /usr/local/sbin after
    pathmunge /usr/sbin after
fi

HOSTNAME=$(/usr/bin/hostnamectl --transient 2>/dev/null) || \
HOSTNAME=$(/usr/bin/hostname 2>/dev/null) || \
HOSTNAME=$(/usr/bin/uname -n)

HISTSIZE=1000
if [ "$HISTCONTROL" = "ignorespace" ] ; then
    export HISTCONTROL=ignoreboth
else
    export HISTCONTROL=ignoredups
fi

export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL

for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then
            . "$i"
        else
            . "$i" >/dev/null
        fi
    fi
done

unset i
unset -f pathmunge

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
[opc@ホスト名 ~]$
[opc@ホスト名 ~]$ cat ~/.bash_profile
# .bash_profile

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

# User specific environment and startup programs
[opc@ホスト名 ~]$
[opc@ホスト名 ~]$ cat ~/.bashrc
# .bashrc

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

# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
    PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH

# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=

# User specific aliases and functions
if [ -d ~/.bashrc.d ]; then
        for rc in ~/.bashrc.d/*; do
                if [ -f "$rc" ]; then
                        . "$rc"
                fi
        done
fi

unset rc
[opc@ホスト名 ~]$
[opc@ホスト名 ~]$ cat /etc/bashrc
# /etc/bashrc

# System wide functions and aliases
# Environment stuff goes in /etc/profile

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

# Prevent doublesourcing
if [ -z "$BASHRCSOURCED" ]; then
  BASHRCSOURCED="Y"

  # are we an interactive shell?
  if [ "$PS1" ]; then
    if [ -z "$PROMPT_COMMAND" ]; then
      case $TERM in
      xterm*|vte*)
        if [ -e /etc/sysconfig/bash-prompt-xterm ]; then
            PROMPT_COMMAND=/etc/sysconfig/bash-prompt-xterm
        else
            PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"'
        fi
        ;;
      screen*)
        if [ -e /etc/sysconfig/bash-prompt-screen ]; then
            PROMPT_COMMAND=/etc/sysconfig/bash-prompt-screen
        else
            PROMPT_COMMAND='printf "\033k%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"'
        fi
        ;;
      *)
        [ -e /etc/sysconfig/bash-prompt-default ] && PROMPT_COMMAND=/etc/sysconfig/bash-prompt-default
        ;;
      esac
    fi
    # Turn on parallel history
    shopt -s histappend
    history -a
    # Turn on checkwinsize
    shopt -s checkwinsize
    [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "
    # You might want to have e.g. tty in prompt (e.g. more virtual machines)
    # and console windows
    # If you want to do so, just add e.g.
    # if [ "$PS1" ]; then
    #   PS1="[\u@\h:\l \W]\\$ "
    # fi
    # to your custom modification shell script in /etc/profile.d/ directory
  fi

  if ! shopt -q login_shell ; then # We're not a login shell
    # Need to redefine pathmunge, it gets undefined at the end of /etc/profile
    pathmunge () {
        case ":${PATH}:" in
            *:"$1":*)
                ;;
            *)
                if [ "$2" = "after" ] ; then
                    PATH=$PATH:$1
                else
                    PATH=$1:$PATH
                fi
        esac
    }

    # Set default umask for non-login shell only if it is set to 0
    [ `umask` -eq 0 ] && umask 022

    SHELL=/bin/bash
    # Only display echos from profile.d scripts if we are no login shell
    # and interactive - otherwise just process them to set envvars
    for i in /etc/profile.d/*.sh; do
        if [ -r "$i" ]; then
            if [ "$PS1" ]; then
                . "$i"
            else
                . "$i" >/dev/null
            fi
        fi
    done

    unset i
    unset -f pathmunge
  fi

fi
# vim:ts=4:sw=4
[opc@ホスト名 ~]$
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?