bash起動ファイルメモ
概要
man
の結果を読んでみたけどぱっとみよくわからないので整理した。
基本的にDokcer(amazonlinux:2)、一部VirtualBox+CentOS7で検証した。
事前準備
次のDockerfileでDockerイメージを作成し、それを使う。
FROM amazonlinux:2 RUN \ yum install -y procps sudo gcc man && \ echo 'echo /etc/profile && echo $- && shopt login_shell' >> /etc/profile && \ echo 'echo .bash_profile && echo $- && shopt login_shell' >> ~/.bash_profile && \ echo 'echo .bash_login && echo $- && shopt login_shell' >> ~/.bash_login && \ echo 'echo .profile && echo $- && shopt login_shell' >> ~/.profile && \ echo 'echo .bashrc && echo $- && shopt login_shell' >> ~/.bashrc && \ echo 'echo .bash_logout && echo $- && shopt login_shell' >> ~/.bash_logout && \ touch ~/.bash_env && echo 'echo .bash_env && echo $- && shopt login_shell' >> ~/.bash_env && \ touch ~/.env && echo 'echo .env && echo $- && shopt login_shell' >> ~/.env && \ useradd mfham -s /bin/bash && \ echo 'echo mfham_.bash_profile && echo $- && shopt login_shell' >> /home/mfham/.bash_profile && \ echo 'echo mfham_.bash_login && echo $- && shopt login_shell' >> /home/mfham/.bash_login && \ echo 'echo mfham_.profile && echo $- && shopt login_shell' >> /home/mfham/.profile && \ echo 'echo mfham_.bashrc && echo $- && shopt login_shell' >> /home/mfham/.bashrc && \ echo 'echo mfham_.bash_logout && echo $- && shopt login_shell' >> /home/mfham/.bash_logout ENV BASH_ENV=~/.bash_env ENV ENV=~/.env
用語
ログインシェル(login shell)
- 0番目の引き数の最初の文字が - であるシェル
--login
オプション付きで起動されたシェル
対話的なシェル(interactive shell)
- オプションでない引き数がなく、標準入力と標準エラー出力がいずれも端末に接続されていて(
isatty(3)
で調べられる)、-c
オプションが指定されていない状態で起動されたシェル -i
オプション付きで起動されたシェル
非対話的なシェル
man
の結果に定義が記載されていないので、対話的なシェルでないものと認識しておく。
bash
bashが対話的なログインシェルとして起動されるか、--login
オプション付きの非対話的シェルとして起動される
/etc/profile
ファイルが存在すれば、ここからコマンドを読み込んで実行する。
その後、~/.bash_profile
, ~/.bash_login
, ~/.profile
の順番で探す。この中で最初に見つかり、かつ読み込みが可能であるファイルからコマンドを読み込んで実行する(最初に見つかったものだけ)。
また、--noprofile
オプションを使ってシェルを起動すれば、/etc/profile
〜~/.profile
読み込みの動作を行わないようにできる。
非対話的なログインシェル(--login
オプションを使わない)
man bash
の記述的に「非対話的なログインシェル(--loginオプションを使わない)」は/etc/profile
を読み込まないと思っていたけど読み込んだ。
Difference between Login Shell and Non-Login Shell? - Unix & Linux Stack ExchangeのAnswer的に、システムによって読まれたり読まれなかったりするのかな?
ログインシェルが終了する
~/.bash_logout
ファイルがあれば読み込んで実行する。
ログインシェルでない対話的シェルとして起動される
~/.bashrc
ファイルがあれば、ここからコマンドを読み込み実行する。
--norc
オプションを使ってシェルを起動すれば、~/.bashrc
読み込みの動作を行わないようにできる。
--rcfile file
オプションを使うと、~/.bashrc
の代わりにfile
から読み込ませることができる。
(例えばシェルスクリプトを実行するために)非対話的に起動される
環境変数 BASH_ENV
を調べ、この変数が定義されていればその値を展開し、得られた値をファイル名とみなして、そこからコマンドの読み込みと実行を行う。
つまり次のコマンドが実行されたのと同じように動作する。
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
ただし、ファイル名を探すためにPATH
環境変数の値が使われることはない。
--posix
コマンドラインオプション等によりPOSIXモードで起動される
起動ファイルに関してPOSIX標準に従う。
このモードでは、対話的シェルはENV
環境変数を展開し、展開して得られた名前のファイルからコマンドの読み込みと実行を行う。
ほかの起動ファイルは全く読み込まない。
リモートシェルデーモンrshd
やセキュアシェルデーモンsshd
によって実行された場合
~/.bashrc
が存在し、かつ読み込み可能であれば、bash
はコマンドをこのファイルから読み込んで実行する。
shとして呼び出された場合には、この動作は行わない。
--norc
オプション、--rcfile
オプションも使うことが可能。
(しかし一般的にはrshd
はこれらのオプションを付けてシェルを起動しないし、指定もできないようになっている)
# VirtualBox+CentOS7での検証 mfham@localhost ~> sudo useradd mfham_test [sudo] mfham のパスワード: # backup mfham@localhost ~> sudo cp /etc/profile /etc/profile_origin # 事前準備1 mfham@localhost ~> sudo su - [root@localhost ~]# echo 'echo /etc/profile' >> /etc/profile && echo 'echo $-' >> /etc/profile && echo 'shopt login_shell' >> /etc/profile # 事前準備2 [root@localhost ~]# su mfham_test [mfham_test@localhost ~]$ echo $SHELL /bin/bash [mfham_test@localhost root]$ cd [mfham_test@localhost ~]$ echo 'echo bash_profile' >>~/.bash_profile && echo 'echo bash_login' >> ~/.bash_login && echo 'echo profile' >> ~/.profile && echo 'echo bashrc' >> ~/.bashrc && echo 'echo bash_logout' >> ~/.bash_logout # ログイン mfham@mac ~> ssh cent7_test mfham_test@****'s password: Last login: Sat Jan 5 05:48:17 2019 /etc/profile himBH login_shell on bashrc bash_profile [mfham_test@localhost ~]$ ps aux | grep mfham_test root 10025 0.3 0.1 159300 6112 ? Ss 05:57 0:00 sshd: mfham_test [priv] mfham_t+ 10027 0.4 0.0 159300 2352 ? S 05:57 0:00 sshd: mfham_test@pts/0 mfham_t+ 10077 0.0 0.0 112724 988 pts/0 R+ 05:58 0:00 grep --color=auto mfham_test # ログインシェルをshに変更 [mfham_test@localhost ~]$ chsh mfham_test のシェルを変更します。 新しいシェル [/bin/bash]: /bin/sh パスワード: シェルを変更しました。 [mfham_test@localhost ~]$ # ログアウト後にログインしなおす mfham@mac ~> ssh cent7_test mfham_test@****'s password: Last login: Sat Jan 5 05:52:10 2019 from **** /etc/profile himBH login_shell on profile -sh-4.2$
シェルが実ユーザ (グループ)IDと異なる実効ユーザ(グループ)IDで起動される
-p
オプションが与えられていない場合- 起動ファイルは全く読み込まれず、シェル関数は環境から継承されず、SHELLOPTS,BASHOPTS,CDPATH,GLOBIGNOREが環境変数に含まれていても無視され、実効ユーザIDには実ユーザIDが設定される。
-p
オプションが起動時に与えられた場合- 起動時の動作は同じだが、実効ユーザIDは再設定される。
参考:
# mfhamユーザでログイン、ログアウト bash-4.2# su - mfham /etc/profile himBH login_shell on mfham_.bashrc himBH login_shell on mfham_.bash_profile himBH login_shell on [mfham@6ac0fadafe8d ~]$ [mfham@6ac0fadafe8d ~]$ exit logout mfham_.bash_logout himBH login_shell on bash-4.2# # bashのパーミッション変更 bash-4.2# ls -l /bin/ | grep bash -rwxr-xr-x 1 root root 964728 Jul 27 18:42 bash lrwxrwxrwx 1 root root 10 Nov 14 07:22 bashbug -> bashbug-64 -rwxr-xr-x 1 root root 6958 Jul 27 18:42 bashbug-64 lrwxrwxrwx 1 root root 4 Nov 14 07:22 sh -> bash bash-4.2# chmod u+s /bin/bash bash-4.2# ls -l /bin/ | grep bash -rwsr-xr-x 1 root root 964728 Jul 27 18:42 bash lrwxrwxrwx 1 root root 10 Nov 14 07:22 bashbug -> bashbug-64 -rwxr-xr-x 1 root root 6958 Jul 27 18:42 bashbug-64 lrwxrwxrwx 1 root root 4 Nov 14 07:22 sh -> bash bash-4.2# # 再度mfhamユーザでログイン bash-4.2# su - mfham Last login: Mon Jan 14 12:48:52 UTC 2019 on pts/0 -bash-4.2$ -bash-4.2$ pwd /home/mfham -bash-4.2$ # 実ユーザID、実効ユーザID確認用スクリプト作成 -bash-4.2$ vi test.c -bash-4.2$ cat test.c #include <stdio.h> #include <unistd.h> #include <sys/types.h> int main() { printf("uid = %d, euid = %d\n", getuid(), geteuid()); getchar(); return 0; } -bash-4.2$ -bash-4.2$ gcc test.c -bash-4.2$ ls -l total 16 -rwxr-xr-x 1 mfham mfham 8328 Jan 14 12:52 a.out -rw-r--r-- 1 mfham mfham 166 Jan 14 12:51 test.c -bash-4.2$ # 確認 -bash-4.2$ ./a.out uid = 1000, euid = 1000 ^C -bash-4.2$ # -pオプションつけてのbash起動後に確認 -bash-4.2$ bash --login -p bash-4.2# ./a.out uid = 1000, euid = 0 ^C bash-4.2#
確認
# 対話的なログインシェル bash-4.2# bash --login /etc/profile himBH login_shell on .bash_profile himBH login_shell on bash-4.2# # --loginオプション付きの非対話的シェル bash-4.2# bash --login -c 'echo foo' /etc/profile hBc login_shell on .bash_profile hBc login_shell on .bash_env hBc login_shell on foo bash-4.2# # 非対話的なログインシェル(--loginオプションを使わない) bash-4.2# ln -s /bin/bash /bin/-bash bash-4.2# -bash -c 'echo foo' /etc/profile hBc login_shell on .bash_profile hBc login_shell on .bash_env hBc login_shell on foo bash-4.2# # --noprofileオプションを使って起動 bash-4.2# bash --login --noprofile bash-4.2# # logout bash-4.2# bash --login /etc/profile himBH login_shell on .bash_profile himBH login_shell on bash-4.2# exit logout .bash_logout himBH login_shell on bash-4.2# # ログインシェルでない対話的シェルとして起動 bash-4.2# bash -i .bashrc himBH login_shell off bash-4.2# # ログインシェルでない対話的シェルとして起動(--norcオプション) bash-4.2# bash --norc -i bash-4.2# # ログインシェルでない対話的シェルとして起動(--rcfileオプション) bash-4.2# touch tmp_file && echo 'echo tmp_file && echo $- && shopt login_shell' >> tmp_file bash-4.2# bash --rcfile tmp_file -i tmp_file himBH login_shell off bash-4.2# # 非対話的に起動 bash-4.2# bash -c 'echo foo' .bash_env hBc login_shell off foo bash-4.2# # 対話的なログインシェル(--posixオプション) bash-4.2# bash --login --posix .env himBH login_shell on bash-4.2#
shという名前でbashを起動
bash
は古くからあるsh
の起動動作をできるだけ真似しようとし、またPOSIX標準にもできるだけ従おうとする。
参考:
# shはbashのalias bash-4.2# ls -l /bin/ | grep sh -rwxr-xr-x 1 root root 964728 Jul 27 18:42 bash lrwxrwxrwx 1 root root 10 Nov 14 07:22 bashbug -> bashbug-64 -rwxr-xr-x 1 root root 6958 Jul 27 18:42 bashbug-64 lrwxrwxrwx 1 root root 19 Nov 14 07:22 setup-nsssysinit -> setup-nsssysinit.sh -rwxr-xr-x 1 root root 1539 Oct 3 18:20 setup-nsssysinit.sh lrwxrwxrwx 1 root root 4 Nov 14 07:22 sh -> bash -rwxr-xr-x 1 root root 37368 Jul 31 20:17 sha1sum -rwxr-xr-x 1 root root 37384 Jul 31 20:17 sha224sum -rwxr-xr-x 1 root root 37384 Jul 31 20:17 sha256sum -rwxr-xr-x 1 root root 37400 Jul 31 20:17 sha384sum -rwxr-xr-x 1 root root 37400 Jul 31 20:17 sha512sum -rwxr-xr-x 1 root root 54104 Jul 31 20:17 shred -rwxr-xr-x 1 root root 50216 Jul 31 20:17 shuf # 起動ファイルの読み込みを行った後にPOSIXモードに入る bash-4.2# bash -c 'echo <(ls)' /dev/fd/63 bash-4.2# sh -c 'echo <(ls)' sh: -c: line 0: syntax error near unexpected token `(' sh: -c: line 0: `echo <(ls)'
対話的なログインシェルとして起動される、あるいは--login
オプション付きの非対話的シェルとして起動される
まず/etc/profile
と~/.profile
の順でコマンドの読み込みと実行をしようとする。
また、--noprofile
オプションを使ってシェルを起動すれば、/etc/profile
、~/.profile
読み込みの動作を行わないようにできる。
対話的シェルとして起動される
環境変数ENV
を調べ、この変数が定義されていればその値を展開し、展開で得た値をコマンドの読み込みと実行を行うためのファイル名として使う。
また、ほかの起動ファイルからコマンドの読み込みと起動を行うことはないので、--rcfile
オプションは全く効果を持たない。
非対話的シェルとして起動される
ほかの起動ファイルを何も読み込まない。
(bash
という名前で非対話的シェルとして起動した場合は、先述の通りBASH_ENV
の参照)
確認
# 対話的なログインシェル bash-4.2# sh --login /etc/profile himBH login_shell on .profile himBH login_shell on .env himBH login_shell on sh-4.2# # --loginオプション付きの非対話的シェル bash-4.2# sh --login -c 'echo foo' /etc/profile hBc login_shell on .profile hBc login_shell on foo bash-4.2# # 非対話的なログインシェル(--loginオプションを使わない) bash-4.2# ln -s /bin/bash /bin/-sh bash-4.2# -sh -c 'echo foo' /etc/profile hBc login_shell on .profile hBc login_shell on foo bash-4.2# # --noprofileオプションを使って起動 bash-4.2# sh --login --noprofile .env himBH login_shell on sh-4.2# # ログインシェルでない対話的シェル bash-4.2# sh -i .env himBH login_shell off sh-4.2# # 対話的なログインシェル bash-4.2# sh --login /etc/profile himBH login_shell on .profile himBH login_shell on .env himBH login_shell on sh-4.2# # --rcfileオプションを使って起動 bash-4.2# touch tmp_file && echo 'echo tmp_file && echo $- && shopt login_shell' >> tmp_file bash-4.2# sh --login --rcfile tmp_file /etc/profile himBH login_shell on .profile himBH login_shell on .env himBH login_shell on sh-4.2# # 非対話的シェルとして起動 bash-4.2# sh -c 'echo foo' foo bash-4.2#
まとめ
- 知らぬも困らぬが役に立つ
/etc/profile
の中身もあわせて理解しておきたい- こういう検証にDocker使うの便利
- 私は最近
fish
シェルを使っている