在Ubuntu的日常运维中,sudo几乎是绕不开的命令。它让普通用户以受控的方式获得root权限,而这一切的规则都写在/etc/sudoers文件里。这个文件一旦被错误编辑,比如少了逗号、写错用户名、括号不匹配,sudo就会直接罢工,报出类似sudo: parse error in /etc/sudoers near line 23的错误。更麻烦的是,如果你当前没有root密码,sudo失效就意味着彻底失去管理系统的能力。本文将系统讲解sudoers文件的修复思路和具体操作步骤。

一、为什么sudoers文件如此脆弱
sudoers文件有一套自己的语法体系,由visudo内部调用的解析器负责解释。这套语法并不复杂,但格式要求非常严格。例如授权规则的基本格式是:用户 主机=(执行身份) 命令,字段之间必须用空格或制表符分隔。如果写成了中文逗号、全角空格,或者把NOPASSWD拼成了NOPASSWD:以外的形式,解析就会失败。
问题的关键在于:sudoers文件损坏的后果是不对称的。改对了,只是多了一条授权;改错了,整个sudo机制瘫痪,而且往往在你退出当前终端之后才发现问题。为了避免这种情况,sudo官方提供了visudo工具,它会在保存前自动做语法检查,检查不通过就拒绝写入,并提示你回退或重新编辑。很多事故的根源就是直接用vim或nano编辑了sudoers文件,跳过了这道安全检查。
另一个容易踩的坑是/etc/sudoers.d目录。Ubuntu默认在sudoers文件末尾包含一行@includedir /etc/sudoers.d,这个目录下的每个文件都会被当作sudoers片段解析。如果某个片段文件名包含点号(如user.rule)或以波浪号结尾,会被直接忽略;如果内容有语法错误,同样会导致sudo报错。排查问题时不要只盯着主文件。
二、sudo还能用时的修复方法
如果你编辑保存后,当前终端的sudo突然报parse error,先别慌。首先测试root shell是否可用:Ubuntu默认锁定root账户,但如果你曾设置过root密码,可以直接执行su -切换到root身份,然后用任何编辑器修复文件。
如果root不可用,还有一个常见的自救场景:visudo编辑过程中出现语法错误时,它会给出明确提示,问你要重新编辑(e)、撤销更改(x)还是退出并保存(Q)。此时务必不要选Q,选e回到编辑器修正错误即可。实际操作中的错误信息类似下面这样:
$ sudo visudo >>> /etc/sudoers: syntax error near line 28 <<< What now? Options are: (e)dit sudoers again (x)it without saving changes to sudoers file (Q)uit and save changes to sudoers file (DANGER!)
保存前验证的另一种方式是手动执行检查命令,对已存在的文件做一次语法校验:
# 校验主文件 visudo -c # 校验包括 sudoers.d 目录在内的所有文件 visudo -c -f /etc/sudoers # 校验单个片段文件 visudo -f /etc/sudoers.d/myrule
养成习惯:任何对sudoers的修改都通过sudo visudo完成,改完先visudo -c确认输出parsed OK再退出,可以把风险降到最低。
三、sudo完全失效后的三种抢救途径
最糟糕的情况是所有用户都失去了sudo权限,root密码也没有设置。这时仍然有办法,因为Linux本质上不依赖sudoers来验证root身份,只要你能拿到一个root shell,就能直接编辑文件恢复。
第一种途径是恢复模式(Recovery Mode)。重启机器,在GRUB菜单选择Advanced options for Ubuntu,再选择带recovery mode的内核条目,进入后选择root选项获得root shell。此时根分区默认以只读方式挂载,需要先重新挂载为可写:
# 以读写方式重新挂载根分区 mount -o remount,rw / # 修复文件,例如删除错误的自定义片段 rm /etc/sudoers.d/broken_rule # 或者直接编辑主文件 visudo # 修复后同步并重启 sync reboot
第二种途径适用于云服务器等无法接触GRUB的场景:通过云厂商控制台的VNC或串口终端,用同样方式进入救援系统,或者把系统盘挂到另一台正常机器上修改。物理机上等价的做法是第三种途径——LiveCD救援:用Ubuntu安装盘启动,选择Try Ubuntu,然后挂载原系统分区进行修复:
# 确认原系统根分区,例如 /dev/sda1 lsblk # 挂载到临时目录 sudo mount /dev/sda1 /mnt # 修复其中的 sudoers 文件 sudo visudo -f /mnt/etc/sudoers # 检查片段目录 ls /mnt/etc/sudoers.d/ # 完成后卸载重启 sudo umount /mnt sudo reboot
三种途径的核心逻辑相同:绕过sudo的授权检查,以root身份直接改文件。因此在操作时要特别注意,恢复模式下改完文件务必执行sync并正常重启,避免文件系统因异常断电造成二次损坏。
四、规范写法与预防措施
修复之后,更重要的是不再犯同样的错误。授权规则的标准写法示例如下:
# 允许 deploy 用户免密执行 systemctl restart myapp deploy ALL=(root) NOPASSWD: /bin/systemctl restart myapp # 允许 ops 组成员执行所有命令但需要密码 %ops ALL=(ALL:ALL) ALL # 限制用户只能以 www-data 身份执行特定脚本 alice ALL=(www-data) /opt/scripts/deploy.sh
写规则时注意几个细节:命令建议使用绝对路径,可通过which systemctl查询;用户组前必须加百分号;(ALL:ALL)表示可切换的执行身份和组身份;一行写不下时用反斜杠续行,反斜杠后不能有空格。自定义规则推荐放到/etc/sudoers.d目录下的独立文件中,文件名只用字母数字和下划线,这样即使某个片段出错,定位起来也更快。
最后建议为关键账户准备一条后路:要么设置一个强密码的root账户作为应急,要么确保至少两个用户拥有sudo权限,或者保留一个可用的串口、VNC控制台访问通道。sudoers文件是系统权限的咽喉要道,修改前花一分钟做备份(cp /etc/sudoers /etc/sudoers.bak),改完用visudo -c验证,就能避免绝大多数锁死系统的尴尬局面。