| 指令 | 類型 | sudo 能否執行 |
cd | Shell 內建指令 | ❌ 無法執行 |
ll | Shell 別名 (alias ll='ls -l') | ❌ 無法執行 |
ls | 外部執行檔 (/bin/ls) | ✅ 正常執行 |
深度原理
Shell 內建指令
cd 是 Shell 內建指令,執行時不創建子進程,直接在當前 Shell 進程中改變工作目錄。sudo 機制是 fork 子進程並在提升權限後執行外部程式。內建指令無法透過 fork/exec 機制在子進程執行,因此 sudo cd 無意義——即使成功也只會改變子進程目錄,不影響父 Shell。
Shell 別名
ll 通常是 alias ll='ls -l' 定義的別名,僅存在於當前 Shell 會話中。sudo 啟動新的非互動式 Shell,不會載入使用者的 .bashrc/.bash_profile,因此別名不存在。
解決方案
方案一:使用完整路徑或參數
# 替代 sudo cd
sudo bash -c 'cd /tmp && pwd'
# 替代 sudo ll
sudo ls -l
sudo ls -la
方案二:在 sudo 環境中啟用別名
# 在 /etc/sudoers 中保留環境變數
Defaults env_keep += "BASH_ENV"
# 在 ~/.bashrc 定義別名並確保非互動式載入
# ~/.bashrc
alias ll='ls -l'
# 強制非互動式也載入
[[ $- != *i* ]] && return # 移除或註解這行
方案三:使用 sudo -s 或 sudo -i
sudo -s # 啟動 root Shell,載入 root 的 .bashrc
sudo -i # 模擬 root 登入,載入完整環境
# 然後在 root Shell 中直接執行
cd /tmp
ll
sudoers 配置最佳實踐
# 使用 visudo 編輯
visudo
# 常用配置範例
# 允許特定用戶無密碼執行特定命令
username ALL=(ALL) NOPASSWD: /bin/systemctl restart nginx
# 保留特定環境變數
Defaults env_keep += "http_proxy https_proxy"
# 記錄輸入/輸出
Defaults log_input, log_output