Title here
Summary here
Shell 嘅啟動方式會影響環境變量嘅加載過程,可以分為以下幾種。
乜嘢係互動式 Shell
An interactive shell is one started without non-option arguments (unless -s is specified) and without specifying the -c option, whose input and error output are both connected to terminals (as determined by isatty(3)), or one started with the -i option.
An interactive shell generally reads from and writes to a user’s terminal.
The -s invocation option may be used to set the positional parameters when an interactive shell is started.
互動式 Shell 係指喺啟動時冇非選項參數(除非指定咗 -s 選項),並且冇指定 -c 選項,其輸入同錯誤輸出都連接到終端(由 isatty(3) 判斷),或者係通過 -i 選項啟動嘅 Shell。
互動式 Shell 通常從用戶嘅終端讀取並向終端寫入內容。
當啟動互動式 Shell 時,可以使用 -s 選項嚟設置位置參數。
喺 Ubuntu 中,使用 SSH 登錄時,文件嘅加載流程大致如下。
/etc/profile
:入口文件 - A,所有用戶都會執行。/etc/bash.bashrc
:全局環境配置文件,A 會加載此文件。/etc/profile.d
:全局環境配置目錄,A 會加載此目錄嘅所有文件。~/.profile
:用戶環境配置入口文件 - B。~/.bashrc
:用戶環境配置文件,B 會加載此文件。rc(Run Commands),源於 Unix 傳統。
system-wide
:系統範圍嘅配置文件。
# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).
# 檢查提示符變量 PS1 是否被設置
if [ "${PS1-}" ]; then
# 檢查 BASH 變量是否被設置,且佢嘅值是否唔等於 /bin/sh
if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
# The file bash.bashrc already sets the default PS1.
# PS1='\h:\w\$ '
# 如果 bash.bashrc 文件存在,則加載
if [ -f /etc/bash.bashrc ]; then
. /etc/bash.bashrc
fi
else
# 當前用戶嘅 id 是否等於 0 (root)
if [ "$(id -u)" -eq 0 ]; then
# root 用戶提示符設為 #
PS1='# '
else
# 普通用戶提示符設為 $
PS1='$ '
fi
fi
fi
# profile.d 目錄是否存在
if [ -d /etc/profile.d ]; then
# 遍歷目錄下嘅所有 sh 文件
for i in /etc/profile.d/*.sh; do
# 如果文件可讀,則加載
if [ -r $i ]; then
. $i
fi
done
unset i
fi
文件內容有啲多,就睇幾行註釋吧。
# System-wide .bashrc file for interactive bash(1) shells.
# To enable the settings / commands in this file for login shells as well,
# this file has to be sourced in /etc/profile.
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
如果唔係互動式(PS1 變量冇設置),則直接退出。
睇一睇目錄嘅文件就好啦。
ls -l /etc/profile.d
total 24
-rw-r--r-- 1 root root 96 Oct 15 2021 01-locale-fix.sh
-rw-r--r-- 1 root root 835 Apr 8 2022 apps-bin-path.sh
-rw-r--r-- 1 root root 726 Nov 16 2021 bash_completion.sh
-rw-r--r-- 1 root root 1107 Mar 23 2022 gawk.csh
-rw-r--r-- 1 root root 757 Mar 23 2022 gawk.sh
-rw-r--r-- 1 root root 1557 Feb 17 2020 Z97-byobu.sh
呢個文件會去加載我哋常常用到嘅 ~/.bashrc
文件。
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.
# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
PATH="$HOME/.local/bin:$PATH"
fi
看頭部註釋可以得知,如果 ~/.bash_profile
同 ~/.bash_login
存在咗話,~/.profile
係唔會被加載嘅,文件加載順序如下。
bash_profile > bash_login > profile
下面分析一下頭部就差不多啦。
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
看第一行註釋,呢個文件會被非登錄 Shell 執行。
前面講到 ~/.profile
文件亦會加載呢個文件,也就係講登錄式 Shell 同非登錄式 Shell 都會用到呢個文件。
再來分析一下呢啲魔法代碼(真係天才設計🤪):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
$-
係一個特殊變量,表示當前 Shell 運行時啟用嘅選項,可以打印出來。
echo $-
himBHs
*i*
係一個匹配條件: $-
中是否包含 i
。i
選項表示當前 Shell 係互動式嘅。總結:如果唔係喺互動式中運行,直接退出,唔做咩。
呢度討論嘅係非登錄嘅情況。例如:
()
執行命令分組時生成嘅 Subshell。一句話總結:唔加載 /etc/profile
,只加載 ~/.bashrc
。
呢種方式冇命令行提示符,唔會加載任可配置文件,即使手動加載 ~/.bashrc
,亦唔會生效。
因為上面嘅分析裡提到,喺非互動式中,會直接退出,唔做咩。
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
當然,你可以使用 BASH_ENV 變量嚟設置加載嘅文件,解釋如下。
If this variable is set when Bash is invoked to execute a shell script, its value is expanded and used as the name of a startup file to read before executing the script. See Bash Startup Files.
只需把環境變量寫喺對應嘅文件中,如:~/.bashrc
。
echo 'export MY_VARIABLE="my_value"' >> ~/.bashrc
source ~/.bashrc