首页 > Sysadmin > 正文

改用户 UID 前,先停进程再补文件归属

huyuanwen 2026-10-26 Sysadmin

usermod -u 只改 /etc/passwd 里那一行:文件归属存的是数字 UID,家目录之外要手动补,已启动的进程也不会跟着变。

先分清 UID 存在哪两处

id -u alice
getent passwd alice
ls -n /srv/data/report.log
find /srv/data -nouser -print

账号表里的 UID 和文件里的数字 UID 是两套东西:权限判定用的是文件里那个数字,用户名只是运行时拿账号表换算出来的。find 的 -nouser 定义就是”没有用户对应到这个文件的数字 UID” [4]——改完 UID 后用它扫一遍,能把没被换算的残留文件捞出来。WSL 实测:改 UID 后目录外的文件仍显示 9606(没有对应名字),find -nouser 正好把它列出来。

动手前:停进程、确认新 UID 没被占用

ps -u alice -o pid,ruid,comm
awk -F: '$3==1010 {print}' /etc/passwd
cp -a /etc/passwd /etc/passwd.bak
usermod -u 1010 alice

Debian 手册的 CAVEATS 写得很直:改数字 UID 之前必须确认这个用户没有进程在跑 [2]。WSL 实测印证了这句——有进程时 usermod 直接拒绝,报 usermod: user demouser is currently used by process 430,退出码 8;把该用户的进程停掉再跑才成功。

新 UID 必须没被占用(除非加 -o),且必须非负 [1]。实测:撞号时报 usermod: UID '1000' already exists(退出码 4),-5 报 invalid user ID(退出码 3);-o 确实能强行写入重复 UID(实测两个账号同时落到 200),但文件归属会一起混淆,生产上不建议。手册还说明 usermod 不会对照 /etc/login.defs 的 UID_MIN/UID_MAX 做检查 [1],而这两个默认值是 1000 和 60000 [5]:实测 Ubuntu 里 useradd -u 200 只给一条警告照样建号,和系统账号撞号往往就是这么来的——新 UID 建议落在普通用户区间。

家目录会自动改,目录外要自己补

手册对 -u 的措辞是:用户邮箱和家目录里属于该用户的文件会被自动改,家目录之外的归属必须手动补 [1]。补的写法用 GNU 手册那条:

find /srv/data -uid 1001 -print0 | xargs -0 chown -h --from 1001 1010

-h 不改符号链接本身,--from 只处理还属于旧 UID 的文件,重复跑或扫错范围时更安全;手册原例是 find / -owner alice -print0 | xargs -0 chown -h bob,改 UID 之后 -owner 已经换算不出名字,只能按数字 UID 扫 [3]。手册同时提醒:从 find 判定到 chown 执行之间有空档,被扫目录若其他人可写会有窗口,别在 /tmp 这类共享目录上跑这条 [3]。

两个实测细节值得留意:

  • 家目录本身的 owner 如果和当前或新 UID 不同,手册明确说里面的文件不做处理,这是针对 / 这类特殊家目录的安全措施 [1]。我按这个条件复现了一次:家目录 owner 改成 root 后跑 usermod,里面那个文件仍是 9404。
  • 硬链接共享同一个 inode,归属是 inode 级的,一次 chown 会把同一文件的所有名字一起改掉,按路径拆不开 [3]。
  • 已登录的会话、cron 和目录服务要单独处理

    crontab -u alice -l
    systemctl restart app-worker
    su - alice -c 'id -u'

    已启动的进程不会回溯:实测改之前起的进程 ps 里仍是 9101,改完后新起的会话才是新 UID——这正是 usermod 宁可拒绝、要求先停进程的原因 [2]。cron 和 at 的作业手册要求手动改 [2]。如果 UID 来自 NIS/LDAP 目录服务,改本地 /etc/passwd 没有意义,要在服务端处理(这一条只核对了文档,尚未在实机验证)。改 GID 是另一回事:groupmod -g 只改组表,实测跑完文件 gid 仍是旧值,要补归属同样得走 chown。

    回滚与排错速查

  • 改错 UID:usermod -u 1001 alice 改回,再把文件 chown 回去;改前的 cp -a /etc/passwd 备份就是回滚依据。
  • 报 currently used by process N:先停该用户的进程(pkill -u alice 或重启该用户的常驻服务)再跑。
  • 报 UID already exists:换未占用的数字,别用 -o 绕过去。
  • 文件显示成数字而不是用户名:说明该 UID 在账号表里已没有对应,属正常现象,补完 chown 就恢复。
  • 改完 UID 登录正常但权限乱:漏了 find + chown 那一步。
  • 局限:测试跑在 WSL Ubuntu 24.04(本地账号,shadow 工具链 4.13),RHEL/Fedora 的 SELinux、NFS 的 root squash、容器镜像内 UID、重启后目录服务行为均未实测。草稿待审;除 NIS/LDAP 那条基于文档核查外,文中命令均已在 WSL 实机执行。

  • 参考资料

    文中主要命令已在 WSL Ubuntu(24.04)实测,个别条目(未装工具/安装类命令)仅核对官方文档,未实际执行。