HOWTO · Linux

登入 Shell 和非登入 Shell 之間的區別

本教程解釋了基於 UNIX 的系統中登入 shell 和非登入 shell 之間的區別。

本頁內容

登入 shell 與非登入 shell 的差異,在於 shell 如何啟動,這會影響啟動設定。本指南說明 UNIX 系統上的這項差異,並以 Bash 示範如何檢查 shell 狀態及選擇啟動方式。登入狀態與 shell 是否為互動式彼此獨立。

什麼是 Shell?

Shell 是一種讀取命令並要求作業系統執行命令的程式。Bash 是常見的 shell 之一。Shell 也可以讀取設定檔,用來設定變數、定義別名及設定提示字元。Bash 會讀取哪些檔案,取決於它的啟動方式,因此同一位使用者在不同工作階段中可能會看到不同設定。

這裡有兩項重要屬性:shell 以登入模式啟動時,就是登入 shell;從面向使用者的提示字元讀取命令時,則是互動式。這兩項屬性彼此獨立。終端機可以啟動互動式的非登入 shell,而指令碼也可以啟動非互動式 shell。

登入 Shell 與非登入 Shell

登入 shell 是以登入模式啟動的 shell。對 Bash 而言,使用 --login 啟動,或以類似登入 shell 的名稱啟動,都屬於這種情況。這項狀態描述 shell 的啟動方式;單憑它無法證明曾經進行驗證,也不能證明使用者登入工作階段已開始。文字主控台登入、SSH 及切換使用者的工具,都是可能啟動登入 shell 的常見情境,實際情況取決於命令與設定。登入 shell 的定義並不是由 /bin/login 啟動的第一個程序;該程式只是登入流程中可能出現的一個環節。

非登入 shell 是在未啟用登入模式的情況下啟動的 shell。互動式 shell 啟動另一個 shell,或終端機模擬器開啟新的提示字元時,常會出現這種情況。為執行命令或指令碼而啟動的 shell 通常是非互動式,也不一定是登入 shell。這些都是常見模式,並非每種終端機或服務都必然如此。

屬性 登入 shell 非登入 shell
意義 以登入模式啟動 未以登入模式啟動
常見設定 登入啟動檔案 互動式 Bash 通常會讀取 ~/.bashrc
獨立屬性 可以是互動式或非互動式 可以是互動式或非互動式

Bash 啟動檔案的差異

Bash 的登入 shell 會先讀取 /etc/profile,接著讀取 ~/.bash_profile、~/.bash_login 和 ~/.profile 中第一個可讀取的使用者檔案。這些檔案可以再載入其他設定。Bash 不會一律透過登入檔案載入 ~/.bashrc;使用者通常會自行加入該行設定。互動式非登入 Bash 會讀取 ~/.bashrc。非互動式 Bash 則會在 BASH_ENV 指定檔案時使用該檔案。/etc/bashrc 等發行版檔案,或 /etc/profile.d 目錄下的檔案,在某些系統上會由系統或使用者設定載入;這並非 Bash 通用且固定的啟動順序。

載入順序很重要,因為後載入的指定可能會取代先前的值。如果某項設定只在某一類工作階段中出現,請先確認 shell 的登入與互動狀態,再檢查相應的啟動檔案及其載入的其他檔案。變更啟動檔案會影響之後啟動的 shell,不會自動更新已在執行中的 shell。

如何辨識及啟動各種 Shell 類型

在 Bash 中,login_shell shell 選項可直接檢查登入狀態。選項開啟時,shopt -q 會回傳成功。登入 shell 的 $0 名稱可能以 - 開頭,但程式和包裝程式可能會改變這個名稱,因此它只能作為線索,不能當成確定的判斷方式。若要另外檢查互動狀態,請確認 $- 旗標是否包含 i。

執行以下 Bash 範例,檢查目前的 shell,並以明確指定的模式啟動子 shell:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

printf 'Current Bash login status: '
if shopt -q login_shell; then
  printf 'login\n'
else
  printf 'non-login\n'
fi

printf 'Child Bash login status: '
bash --login -c 'if shopt -q login_shell; then printf "login\\n"; else printf "non-login\\n"; fi'

case $- in
  *i*) printf 'Current Bash is interactive\n' ;;
  *)   printf 'Current Bash is non-interactive\n' ;;
esac
Current Bash login status: non-login
Child Bash login status: login
Current Bash is non-interactive

使用 bash --login 要求啟動登入 Bash,使用 bash 則會啟動非登入 Bash。只有在需要互動式子 shell 時才加上 -i;互動式 shell 不會自動成為登入 shell。例如,bash --login -i 會同時要求這兩種屬性。測試啟動行為時,請使用新的 shell,並留意本機設定可能會載入其他檔案。

標示為登入 shell 的終端機示意圖

標示為非登入 shell 的終端機示意圖