在 Linux 系統管理中,su(Switch User)命令是實現用戶身份切換的基石工具。它不僅能讓普通用戶提權為超級用戶,也能在不同普通用戶間切換。然而,許多初學者對其底層運作機制存在誤解:執行 su 後,原用戶的會話去哪了?為什麼無法直接刪除原用戶?本文將從進程模型、用戶 ID 概念、實戰案例三個維度,徹底講透 su 的本質。
要理解 su,必須先搞清 Unix/Linux 進程的兩個關鍵屬性:
s 位),程序執行時可暫時獲得文件擁有者的權限。su 命令本身擁有 Setuid 權限(-rwsr-xr-x),屬於 root。當普通用戶執行 su 時,進程的 Real UID 仍是該用戶,但 Effective UID 變為 0(root),從而獲得特權操作能力。
這是最關鍵的認知點:su 不會終結原有 Shell 進程,而是創建一個新的子 Shell 進程。
當 root 執行 su - user1 時:
fork() 創建子進程。exec() 載入 su 程序,驗證密碼通過後,再次 exec() 載入目標用戶的 Shell(如 bash)。root bash (2939) → su (2958) → user1 bash (2966)。原 root Shell 進程(2939)依然存在,只是處於等待狀態。這解釋了為什麼執行 exit 或 Ctrl+D 會「返回」原用戶——實際上只是結束子 Shell,控制權交還給父 Shell。
who am i vs whoami兩個命令的區別完美印證了上述機制:
who am i:查詢 utmp 記錄,顯示登錄會話的原始用戶(Real UID 對應的登錄信息)。whoami:顯示當前進程的有效用戶名(Effective UID)。案例演示:
root@host:~# who am i
root pts/0 2023-10-01 10:00 (:0.0)
root@host:~# whoami
root
root@host:~# su - user1
user1@host:~$ who am i
root pts/0 2023-10-01 10:00 (:0.0) <-- 登錄會話仍屬 root
user1@host:~$ whoami
user1 <-- 當前有效身份為 user1
進程列表(ps -ef)清晰可見父子鏈路:
root 2939 2935 0 10:00 pts/0 00:00:00 bash
user1 2958 2939 0 10:01 pts/0 00:00:00 su - user1
user1 2966 2958 0 10:01 pts/0 00:00:00 -bash
su 後嘗試刪除原用戶,提示 "user logged in",為什麼?A: 因為原用戶的登錄 Shell 進程(父進程)仍在運行,系統檢測到該用戶仍有活躍會話。必須先 exit 退出子 Shell,或殺掉父進程(kill -9 父PID),才能釋放會話。
su 和 su - 有何區別?A: su -(或 su -l)會啟動「登錄 Shell」,重新讀取目標用戶的環境變量(PATH、HOME 等),切換工作目錄至其家目錄;而單純 su 保留當前環境,僅切換有效 UID。
su 的本質是利用 Setuid 機制創建特權子進程,而非替換當前會話。理解「父子進程」、「Real UID vs Effective UID」、「登錄 Shell vs 非登錄 Shell」這三組概念,即可洞悉用戶切換的所有行為表現。掌握這一機制,不僅能解決操作疑惑,更是掌握 Linux 權限模型的關鍵一環。
