Linux useradd 后没有家目录?加了组不生效?sudoers 写错一个文件 sudo 全挂?三台真机实测用户与权限
这一篇讲什么用户和权限的命令都很简单,坑在于同一条命令,三个发行版的默认行为不一样,以及改完了,但对已经在跑的东西不生效。本篇在三台机器上逐个复现,贴原始输出。机器:CentOS 7.9(VMware)、Rocky 9.8、Ubuntu 24.04.5(后两台是 LXD 虚拟机,cloud 镜像)。1. useradd:Ubuntu 上不建家目录,shell 是 sh ✅同样一条useradd labu1,不带任何参数:labu1:x:1000:1000::/home/labu1:/bin/bash (Rocky 9) drwx------. 2 labu1 labu1 4096 Sep 21 17:42 /home/labu1 labu1:!! labu1:x:1000:1000::/home/labu1:/bin/sh (Ubuntu 24.04) ls: cannot access /home/labu1: No such file or directory labu1:!CentOS 7 和 Rocky 9 一样。Ubuntu 上:不建家目录——/etc/passwd里写着/home/labu1,目录却不存在;shell 是/bin/sh(Ubuntu 上它是 dash,不是 bash)。原因在默认配置里:HOME/home SHELL/bin/sh (Ubuntu 24.04,useradd -D) CREATE_HOME yes (Rocky 9 的 /etc/login.defs;Ubuntu 没有这一行)跨发行版的脚本,一律写全:useradd -m -s /bin/bash。另外,adduser在 CentOS 7 / Rocky 9 上只是个软链:lrwxrwxrwx. /usr/sbin/adduser - useraddUbuntu 上adduser是一个独立的交互式程序,会建家目录、问密码。2. passwd --stdin:Ubuntu 上没有 ✅脚本里批量设密码的常见写法:passwd: all authentication tokens updated successfully. (CentOS 7 / Rocky 9) passwd --stdin 退出码0 passwd --stdin 退出码6 (Ubuntu 24.04)--stdin是 RHEL 系 passwd 的扩展。通用写法是chpasswd,三台都成功:chpasswd 退出码03. usermod -G 忘了 -a,原来的组全没了 ✅加两个组后:uid1000(labu1) gid1000(labu1) groups1000(labu1),1002(labg1),1003(labg2) usermod -G(不带 -a)后:uid1000(labu1) gid1000(labu1) groups1000(labu1),1004(labg3)三台一样。-G是「把附加组设置成这些」,不是「加上这些」。labg1、labg2 被清掉了 —— 如果被清掉的是wheel或sudo,这个用户就没有 sudo 权限了。永远写usermod -aG。4. 加了组,已经在跑的进程不认 ✅usermod -aG labg4 labu1之后:id labu1:labu1 labg3 labg4 已在运行的进程(974)的组:Groups: 1000 1004 labg4 的 GID1005 新登录 su - labu1 -c id:labu1 labg3 labg4三台一样。id labu1查的是配置,显示已经有 labg4 了;但已经在运行的进程(看/proc/PID/status的Groups),组列表是登录那一刻定下来的,里面没有 1005。实际影响:把运行服务的用户加进某个组,服务要重启才能用上新组的权限;给自己加了docker组,要重新登录。5. su 和 su -,PATH 不一样 —— 但 Ubuntu 例外 ✅从PATH/usr/bin:/bin出发切到 root:su: PATH/usr/bin:/bin 目录/root (Rocky 9) su -: PATH/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin 目录/rootsu(不带-)保留原来的 PATH,里面没有/usr/sbin,于是useradd、ip、sysctl这类命令会报「command not found」。CentOS 7 同样(su后仍是/usr/bin:/bin)。Ubuntu 24.04 上su不带-也给了完整的 PATH:su: PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin 目录/root所以同一个问题,在 Ubuntu 上复现不出来。要一个干净的 root 环境,用su -。6. sudo 权限:wheel 还是 sudo 组 ✅%wheel ALL(ALL) ALL (CentOS 7 / Rocky 9) #includedir /etc/sudoers.d %sudo ALL(ALL:ALL) ALL (Ubuntu 24.04) includedir /etc/sudoers.d给用户 sudo 权限:RHEL 系加进wheel,Ubuntu 加进sudo。#includedir开头的#不是注释,是老语法(新版 sudo 改成了),别删。7. sudoers.d 里的文件名带点,整个文件被忽略 ✅在/etc/sudoers.d/里放一个规则,文件名分别叫labu1.conf和labu1:[文件名 labu1.conf] sudo: a password is required [文件名 labu1] 0三台一样(CentOS 7 那台是中文提示「sudo: 需要密码」)。文件名里带.的文件会被跳过,不报错、不警告,规则就是不生效。习惯了xxx.conf的人最容易踩。8. 往 sudoers.d 里放一个语法错误的文件 ✅不用visudo、直接写一个有语法错误的文件(NOPASSWD后面少了冒号):labu2 ALL(ALL) NOPASSWD ALLCentOS 7:root 自己的 sudo 都用不了了:[有一个坏文件时 root 用 sudo] /etc/sudoers.d/labbad: syntax error near line 1 sudo: parse error in /etc/sudoers.d/labbad near line 1 sudo: no valid sudoers sources found, quitting sudo: unable to initialize policy plugin普通用户 labu1 那条正常规则也一起失效。如果这台机器 root 不能直接登录、只能靠 sudo,你就把自己锁在外面了。Rocky 9(sudo 1.9.17p2)/ Ubuntu 24.04(sudo 1.9.15p5):只报错,sudo 照样能用:/etc/sudoers.d/labbad:1:26: syntax error labu2 ALL(ALL) NOPASSWD ALL ^~~ visudo -c 退出码1 [有一个坏文件时 root 用 sudo] /etc/sudoers.d/labbad:1:26: syntax error labu2 ALL(ALL) NOPASSWD ALL ^~~ 退出码0新版 sudo 跳过坏的那一条,其余规则继续生效,还标出了出错的位置。但别指望这个—— 老系统上就是全挂。改 sudoers 一律用visudo(它保存前会检查语法),改sudoers.d下的文件用visudo -f /etc/sudoers.d/xxx,改完visudo -c再检查一遍。9. SGID 共享目录:设了还是不能一起改 ✅经典做法:建一个labproj组,目录属组设成它,加上 SGID(2775),这样组里的人新建的文件自动属于labproj:drwxrwsr-x 2 root labproj 4096 Sep 21 17:42 /data/labprojlabu1 建两个文件,labu2(同组)去追加内容:CentOS 7 / Ubuntu 24.04(登录用户的 umask 是 0002):labu1 的 umask:0002 -rw-rw-r-- 1 labu1 labproj 8 Sep 21 17:42 a.txt -rw-r--r-- 1 labu1 labproj 8 Sep 21 17:42 b.txt u2 追加 a.txt 成功 -bash: line 1: /data/labproj/b.txt: Permission deniedb.txt是用umask 022建的,组没有写权限。Rocky 9:labu1 的 umask:0022 -rw-r--r--. 1 labu1 labproj 8 Sep 21 17:42 a.txt -rw-r--r--. 1 labu1 labproj 8 Sep 21 17:42 b.txt -bash: line 1: /data/labproj/a.txt: Permission denied -bash: line 1: /data/labproj/b.txt: Permission deniedRocky 9 的普通用户默认 umask 就是 0022,新建的文件组只读,两个都改不了。结论:SGID 只管「文件属于哪个组」,不管「组有没有写权限」。要真正共享写,还要保证新文件的组有写权限 —— 上面 CentOS 7 / Ubuntu 的a.txt就是 umask 002 建出来、能共享写的样子。去掉 SGID 后,新文件的属组变回用户自己的组:-rw-rw-r-- 1 labu1 labu1 2 Sep 21 17:42 /data/labproj/c.txt10. 文件是 644,却读不了 —— 看路径上每一层目录 ✅f.txt是 644,所在目录sub是 700(属主 root):cat: /data/labperm/sub/f.txt: Permission deniednamei -l把路径上每一层的权限都列出来:f: /data/labperm/sub/f.txt drwxr-xr-x root root / drwxr-xr-x root root data drwxr-xr-x root root labperm drwx------ root root sub -rw-r--r-- root root f.txt一眼看出卡在sub。访问一个文件,要对路径上每一层目录都有x权限。目录有r没有x(744)时,更诡异:f.txt ls: cannot access /data/labperm/sub/f.txt: Permission denied total 0 -????????? ? ? ? ? ? f.txt cat: /data/labperm/sub/f.txt: Permission denied(Ubuntu 24.04,三台一样。)ls能列出文件名(r管读目录内容),但ls -l看不到属性、cat读不了(x管进入目录访问里面的文件)。11. 删文件看的是目录权限,不是文件权限 ✅在一个 777 的目录里,labu2 建了一个只读文件(444),labu1 去删:-r--r--r-- 1 labu2 labu2 3 Sep 21 17:42 /data/labdel/u2.txt labu1 删掉了 labu2 的只读文件三台一样。删除是修改目录,和文件本身的权限无关。这就是/tmp要加粘滞位(t)的原因:drwxrwxrwt 2 root root 4096 Sep 21 17:42 /data/labdel rm: cannot remove /data/labdel/u2b.txt: Operation not permitted加上t后,只有文件属主(和 root)能删。12. chmod -R 755,把文件也变成了可执行 ✅-rwxr-xr-x 1 root root 0 Sep 21 17:42 a.conf drwxr-xr-x 2 root root 4096 Sep 21 17:42 d urwX,gorX: -rw-r--r-- 1 root root 0 Sep 21 17:42 a.conf drwxr-xr-x 2 root root 4096 Sep 21 17:42 dchmod -R 755让配置文件都带上了x。用大写的X:只给目录(和本来就有x的文件)加执行权限。13. cp 丢了属主和时间 ✅root 复制一个属于 labu1、日期 2020-01-01 的文件:-rw-r----- root root 2026-09-21 /data/labcp/c1 -rw-r----- labu1 labu1 2020-01-01 /data/labcp/c2 -rw-r----- labu1 labu1 2020-01-01 /data/labcp/ownedc1是普通cp:属主变成 root、时间变成今天。c2是cp -a:原样保留。用 root 复制别人的文件或网站目录,不加-a,程序就读不了了。目标目录已存在时,cp -r src dst的结果是dst/src/,不是把 src 的内容放进 dst:/data/labcp/dst /data/labcp/dst/src /data/labcp/dst/src/f14. ln -sf 换不掉指向目录的软链 ✅cur是指向v1目录的软链,想把它改成指向v2:ln -sf 之后 cur - /data/labln/v1;v1 里多了:v2 ln -sfn 之后 cur - /data/labln/v2三台一样。ln -sf v2 cur把cur当成了目录,在v1里面建了一个叫v2的软链,cur本身没变。发布系统用软链切换版本时,这个错误会让你以为切过去了。要加-n。15. find | xargs rm 遇到带空格的文件名 ✅xargs 之后剩:a b.log -print0 之后剩:0 个a b.log被 xargs 拆成了a和b.log两个参数,都不存在,文件留了下来(如果恰好有叫a的文件,删的就是它)。用find ... -print0 | xargs -0,或者直接find ... -delete。16. root 也删不掉的文件 ✅rm: cannot remove /data/labcp/imm: Operation not permitted rm 退出码1 ----i---------e------- /data/labcp/imm chattr -i 后删掉了权限看着正常、root 也删不掉,用lsattr看有没有i(不可修改)属性。17. rm -rf “$DIR”/ 的保险 ✅# DIR; echo rm -rf ${DIR:?}/x; echo 这一行不会执行 bash: line 1: DIR: parameter null or not set变量为空时,${DIR:?}直接报错退出,后面的命令都不会执行。脚本里rm -rf $DIR/一旦 DIR 为空就是rm -rf /,删除类命令里的变量一律写成${DIR:?}。18. userdel 不带 -r,留下一堆无主文件 ✅drwxr-x--- 2 1001 1001 4096 Sep 21 17:42 /home/labu2 /home/labu2 /home/labu2/.profile /home/labu2/.bash_logout用户删了,家目录还在,属主显示成数字 1001。以后新建的用户如果拿到了 1001 这个 UID,这些文件就自动归他了。用find / -nouser找出来处理掉。另外两个小差异:rename:CentOS 7 / Rocky 9 自带(util-linux 版,rename .txt .bak *.txt);Ubuntu 默认没有。locate:三台都没装。小结坑对策Ubuntu useradd 不建家目录、shell 是 shuseradd -m -s /bin/bashUbuntu 没有passwd --stdin用chpasswdusermod -G清掉原有组usermod -aG加组后服务没权限重启服务 / 重新登录su后找不到命令su -sudoers.d 规则不生效文件名不能带.一个坏文件让 sudo 全挂(CentOS 7)用visudo -fSGID 目录还是改不了别人的文件保证 umask 是 002644 的文件读不了namei -l看每层目录chmod -R 755文件都可执行用urwX,gorX软链切换没切过去ln -sfn下一篇:文本处理、压缩与传输 —— sed -i 会破坏软链、tar -cfz 生成一个叫 z 的文件、scp 在新版本上已经不走 scp 协议。