3.9 KiB
Sudo 密码传递模式
常见陷阱:heredoc 消耗密码导致 sudo 认证失败
模式对比
❌ 错误:heredoc 中使用 echo | sudo -S
# 失败:密码在第一个命令后被消耗,sudo 第二次读取时得到空行
echo 'z1020' | sudo -S bash -c 'cat > /etc/file << EOF
some content
EOF
another command' # 这里 sudo 读不到密码
✅ 正确:单条命令直接 pipe
echo 'z1020' | sudo -S sysctl -w vm.swappiness=10
✅ 正确:多条命令用 bash -c(内容不在 heredoc)
# bash -c 的参数是单行字符串,不是 heredoc,密码可重复使用
echo 'z1020' | sudo -S bash -c 'sysctl -w vm.swappiness=10 && sysctl -w net.core.default_qdisc=fq'
✅ 正确:分开执行(最可靠)
# 每条命令独立 pipe,密码各用一次
echo 'z1020' | sudo -S sysctl -w vm.swappiness=10
echo 'z1020' | sudo -S sysctl -w net.core.default_qdisc=fq
echo 'z1020' | sudo -S sysctl -w net.ipv4.tcp_congestion_control=bbr
✅ 正确:用 tee 写入文件(替代 heredoc)
# heredoc 需要交互式 shell,用 tee 代替
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swappiness.conf
根本原因
echo 'password' | sudo -S 中,密码通过 stdin 传递,但:
- Heredoc
<<EOF也会从 stdin 读取内容,把密码吃掉了 sudo -S第一次 read 成功,后续命令重试时 stdin 已耗尽
验证方法
# 检查上条 sudo 命令是否成功
sudo -n true && echo "sudo OK" || echo "sudo failed"
坑 #6:sudo flag 顺序打错(2026-06-28 实测)
症状:单独跑 echo 'pw' | sudo -S -v 接受密码,但换 echo 'pw' | sudo -S <args> 写法立即 [3 incorrect password attempts]。
根因:flag 顺序/组合打错(比如 sudo -S -p '' gpg ...)时 sudo wrapper 抛 usage error,但 sudo 内部认证层把 stdin 已消耗算成"密码不匹配",导致 3 次 fail 锁。
正确(-S 必须独立):
echo 'z1020' | sudo -S gpg --dearmor -o /usr/share/keyrings/microsoft-edge.gpg /tmp/msedge.asc
教训:先在最小可工作命令验证 sudo 接受密码(echo 'pw' | sudo -S whoami),再叠加业务参数。Flag 顺序/组合改一次验证一次。
坑 #7:提议"额外步骤"前没先做 preflight(浪费 3-4 步)
反例(2026-06-28 Edge):
- 用户问要不要加 apt 自动更新源 → 直接跑到加 GPG key 那里,失败 2 次
- 真相:
.deb安装时 post-install hook 早已写好/usr/share/keyrings/microsoft-edge.gpg和/etc/apt/sources.list.d/microsoft-edge.sources,只是我没先看一眼。
正确流程:提议任何"额外配置"前先 fs 探测现状:
ls /etc/apt/sources.list.d/ | grep -i -E 'edge|micros|teams|vscode|...'
ls /usr/share/keyrings/ | grep -i -E 'edge|micros|microsoft|...'
cat /etc/apt/sources.list.d/<name>.list /etc/apt/sources.list.d/<name>.sources 2>/dev/null
规则:先 ls/cat 看现状,再告诉用户"剩什么没做",不要上来就说"我没做 X,要不要我加"。
⚠️ 这条规律适用于大部分 .deb 包:Microsoft 系(Edge 已验证;VS Code/Teams/PowerToys 推测同模式)通常自带 post-install 写源。其他发行包(Chrome / Slack / Discord beta)通常不自带,需要手动加。
坑 #8:用 sudo -v 单独 stamp,回避管道 sudo 反复认证
观察:echo 'pw' | sudo -S <业务命令> 容易踩 sudo flag 顺序/组合边界问题,反复解锁浪费时间。
解决:先 stamp sudo 缓存(默认 5min),之后业务命令直接 sudo <cmd>:
# 一次性输密码
echo 'z1020' | sudo -S -v
# 5 分钟内免密(不指定命令)
sudo dpkg -i /tmp/edge.deb
sudo apt update
前提:5 分钟窗口期内能列出所有 sudo 操作。如果密集 sudo 命令散落在整个 session 里,就只能在每次登录态新发命令时分别 echo | sudo -S。