usermod 命令详解与参数实测(Ubuntu 22.04)
以 Ubuntu 22.04(shadow 4.8.1)实测逐参数讲解 usermod:-aG 追加组与漏 -a 覆盖风险、-L/-U 锁定解锁、-s/-d/-m/-l/-u/-g/-o/-c/-e/-p/-v/-w 全参数真实回显,含 UID 改变后文件属主随迁规则与退出码。
usermod 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 usermod 的每一个常用参数——
-aG追加附加组与漏-a的覆盖风险、-L/-U锁定解锁、-s改 shell、-d -m搬家、-l改名、-u/-g改 UID 与主组、-o重复 UID、-c/-e/-f/-p属性修改、-v/-wsubordinate ID 等全部参数,以及报错行为与退出码,全部命令与回显已在 Ubuntu 22.04(shadow 4.8.1)实测通过。
一、环境信息
本文所有命令均在以下环境实测,回显逐字照抄:
- 操作系统:Ubuntu 22.04.5 LTS(
PRETTY_NAME="Ubuntu 22.04.5 LTS") - 内核架构:x86_64
- usermod 所属软件包:passwd 1:4.8.1-2ubuntu2.2(即 shadow-utils 4.8.1,与 useradd 同包)
- 执行身份:root
- 演示用户:以
u4f为前缀(u4f1、u4f2、u4fown、u4froot、改名后的 u4fnew),演示组:u4fgrp1、u4fgrp2、u4fgrp3 - 演示目录:家目录迁移演示
/home/u4f1 → /srv/u4f1home
💡 说明:系统中另有其他演示用户(如
u4c1、u4c2在 sudo 组中),它们恰好成为-aG sudo场景的现成对照数据;所有u4f前缀账号在实测后均已清理。
二、命令概览
2.1 语法与测试数据
usermod 用于修改已存在用户的各项属性:登录名、UID、主组、附加组、shell、家目录、过期策略、密码哈希、subordinate ID 等,是 useradd 的配套维护工具。语法只有一种形态(来自实测 usermod --help 首行):
Usage: usermod [options] LOGIN
LOGIN 是要修改的已存在用户名,options 与要改的属性一一对应;一次调用可以叠加多个参数(如 usermod -s /bin/bash -c '新注释' 用户名)。
本文测试数据约定:先用 useradd -m -u 1801 -s /bin/sh u4f1 建立基准用户(UID 固定便于观察属主变化),再用 groupadd 准备 u4fgrp1/u4fgrp2/u4fgrp3 三个组;每个参数小节可独立复现。
💡 技术拓展:修改账号属性的同类工具不止 usermod,按「改什么」选工具对比——
工具 负责范围 典型用法 usermod 全属性:名/UID/组/shell/家目录/过期/锁定 本文主角,一站式 passwd 密码本身、有效期( passwd -S/-x/-n)改密、查状态 chage 过期策略(账 号过期、密码周期) chage -l查看、chage -E改过期chfn GECOS 注释(姓名/办公室/电话) 交互式改注释 gpasswd 组成员与组密码(增删单个成员) gpasswd -a 用户 组newgrp / sg 当前会话临时切换主组 不落库,只影响本次会话 本文实际采用 usermod:它能在一条命令里完成上述多数修改并保证与 shadow 工具链一致的锁机制;组成员微调场景 gpasswd 与
usermod -aG等价,见 3.1。
2.2 --help 全量输出(逐行照抄)
以下为 usermod --help 的完整实测输出:
$ usermod --help
Usage: usermod [options] LOGIN
Options:
-b, --badnames allow bad names
-c, --comment COMMENT new value of the GECOS field
-d, --home HOME_DIR new home directory for the user account
-e, --expiredate EXPIRE_DATE set account expiration date to EXPIRE_DATE
-f, --inactive INACTIVE set password inactive after expiration
to INACTIVE
-g, --gid GROUP force use GROUP as new primary group
-G, --groups GROUPS new list of supplementary GROUPS
-a, --append append the user to the supplemental GROUPS
mentioned by the -G option without removing
the user from other groups
-h, --help display this help message and exit
-l, --login NEW_LOGIN new value of the login name
-L, --lock lock the user account
-m, --move-home move contents of the home directory to the
new location (use only with -d)
-o, --non-unique allow using duplicate (non-unique) UID
-p, --password PASSWORD use encrypted password for the new password
-R, --root CHROOT_DIR directory to chroot into
-P, --prefix PREFIX_DIR prefix directory where are located the /etc/* files
-s, --shell SHELL new login shell for the user account
-u, --uid UID new UID for the user account
-U, --unlock unlock the user account
-v, --add-subuids FIRST-LAST add range of subordinate uids
-V, --del-subuids FIRST-LAST remove range of subordinate uids
-w, --add-subgids FIRST-LAST add range of subordinate gids
-W, --del-subgids FIRST-LAST remove range of subordinate gids
-Z, --selinux-user SEUSER new SELinux user mapping for the user account
关键差异解读:-G 与 -a 联用才是「追加」,-G 单用是「全量替换」(本文最大的踩坑点,见 3.2);-d 必须配 -m 才搬文件;-L/-U 是锁定/解锁一对;-v/-V、-w/-W 是 subordinate UID/GID 的增/删一对;-R/-P/-Z/-b 为特定场景低频参数(见 3.15)。
2.3 版本信息
usermod 与 useradd 同属 passwd 软件包(shadow 工具集),版本一致。同样不支持 --version:
$ usermod --version; echo rc=$?
usermod: unrecognized option '--version'
Usage: usermod [options] LOGIN
(随后打印完整 Options 列表,同 2.2)
rc=2
$ dpkg -l passwd | tail -1
ii passwd 1:4.8.1-2ubuntu2.2 amd64 change and administer password and group data
确认版本用 dpkg -l passwd,1:4.8.1 即 shadow-utils 4.8.1。
三、参数逐项实测
3.1 -aG:追加附加组(标准用法)
-a(--append)+ -G(--groups)组合向用户的附加组列表追加组而不影响其他组成员关系,是授权(如 sudo 组)的标准姿势。先建基准用户再追加:
useradd -m -u 1801 -s /bin/sh u4f1
usermod -aG u4fgrp1 u4f1
groups u4f1
id u4f1
usermod -aG u4fgrp1,u4fgrp2 u4f1
groups u4f1
实测回显:
$ useradd -m -u 1801 -s /bin/sh u4f1
$ usermod -aG u4fgrp1 u4f1
$ groups u4f1
u4f1 : u4f1 u4fgrp1
$ id u4f1
uid=1801(u4f1) gid=1801(u4f1) groups=1801(u4f1),1012(u4fgrp1)
$ usermod -aG u4fgrp1,u4fgrp2 u4f1
$ groups u4f1
u4f1 : u4f1 u4fgrp1 u4fgrp2
💡 要点:-G 后可跟逗号分隔的多个组;第二次追加后 u4fgrp1 仍在——-a 的语义就是不移除已有组。落点在 /etc/group 的成员字段(主组关系记录在 /etc/passwd,不受影响)。
3.2 -G:全量替换语义与漏 -a 的覆盖风险(重点)
-G 不加 -a 时,用户的附加组列表被整体替换为参数里的新列表——这是运维事故高发点。实测覆盖现象与恢复:
usermod -G u4fgrp3 u4f1 # 注意:故意漏掉 -a
groups u4f1
grep -E '^u4f(1|grp1|grp2|grp3)' /etc/group
usermod -aG u4fgrp1,u4fgrp2 u4f1 # 恢复
groups u4f1
实测回显:
$ usermod -G u4fgrp3 u4f1
$ groups u4f1
u4f1 : u4f1 u4fgrp3
$ grep -E '^u4f(1|grp1|grp2|grp3)' /etc/group
u4fgrp1:x:1012:
u4fgrp2:x:1013:
u4fgrp3:x:1014:u4f1
u4f1:x:1801:
$ usermod -aG u4fgrp1,u4fgrp2 u4f1
$ groups u4f1
u4f1 : u4f1 u4fgrp1 u4fgrp2 u4fgrp3
💡 要点:
- 覆盖前 u4f1 的附加组是 u4fgrp1、u4fgrp2;漏
-a的-G u4fgrp3执行后,/etc/group里 u4fgrp1、u4fgrp2 的成员字段被清空(u4fgrp1:x:1012:),只剩 u4fgrp3 有成员 u4f1——用户悄悄丢了 sudo 之类的组权限,且命令不报任何警告。 - 主组 u4f1(gid 1801)不受
-G影响,主组只随-g变。 - 经验法则:给已有用户加组永远写
usermod -aG;确要重设整个附加组列表时,先用groups 用户名留底再操作。
3.3 -L:锁定账号 与 -U:解锁
-L(--lock)在 shadow 密码哈希前加 ! 使密码认证失效,-U(--unlock)移除该前缀。用 passwd -S 与 shadow 原文双重验证:
echo 'u4f1:q1w2e3r4' | chpasswd
passwd -S u4f1
usermod -L u4f1
passwd -S u4f1
grep '^u4f1:' /etc/shadow | cut -c1-30
usermod -U u4f1
passwd -S u4f1
实测回显:
$ echo 'u4f1:q1w2e3r4' | chpasswd
$ passwd -S u4f1
u4f1 P 10/15/2026 0 99999 7 -1
$ usermod -L u4f1
$ passwd -S u4f1
u4f1 L 10/15/2026 0 99999 7 -1
$ grep '^u4f1:' /etc/shadow | cut -c1-30
u4f1:!$y$j9T$MPOH6Irv5bLjvhjET
$ usermod -U u4f1
$ passwd -S u4f1
u4f1 P 10/15/2026 0 99999 7 -1
💡 要点:
passwd -S第二列:P有效密码、L已锁定;shadow 原文可见哈希前多了!(u4f1:!$y$...),这就是锁定的实现——顺带确认本机 chpasswd 默认算法是 yescrypt($y$)。-L只挡「密码认证」;root 用su切换该用户不需要密码,因此root 侧 su 不受-L影响,锁定的作用对象是 SSH/登录管理器等密码认证路径。要求「彻底不可登录」应改 shell 为 nologin 或配合-e过期。- 对无密码用户执行
-U时,usermod 会拒绝解锁以免产生空密码账号(提示 unlocking ... would result in a passwordless account),本例因已设密未触发。
3.4 -s:改登录 shell
-s(--shell)修改登录 shell,常用于给误设 shell 的账号纠偏,或把账号降级为 nologin:
usermod -s /bin/bash u4f1
grep u4f1 /etc/passwd
实测回显:
$ usermod -s /bin/bash u4f1
$ grep u4f1 /etc/passwd
u4f1:x:1801:1801::/home/u4f1:/bin/bash
💡 要点:passwd 第 7 字段由 /bin/sh 变为 /bin/bash;正在登录的会话不受影响,用户重新登录后生效。usermod 不校验 shell 路径是否存在,写错路径会导致下次登录失败,改完务必复核 passwd 字段。
3.5 -d -m:搬家家目录(旧家目录内容随迁)
-d(--home)改家目录记录,必须联用 -m(--move-home)才会把旧家目录整个搬走(目录树原样迁移、属主保持)。先造数据再搬家:
touch /home/u4f1/note.txt && mkdir /home/u4f1/proj && echo 'proj data' > /home/u4f1/proj/a.txt
ls -lR /home/u4f1
usermod -d /srv/u4f1home -m u4f1
grep u4f1 /etc/passwd
ls -ld /home/u4f1 /srv/u4f1home
ls -lR /srv/u4f1home
实测回显:
$ touch /home/u4f1/note.txt && mkdir /home/u4f1/proj && echo 'proj data' > /home/u4f1/proj/a.txt
$ ls -lR /home/u4f1
/home/u4f1:
total 4
-rw-r--r-- 1 root root 0 Oct 15 09:03 note.txt
drwxr-xr-x 2 root root 4096 Oct 15 09:03 proj
/home/u4f1/proj:
total 4
-rw-r--r-- 1 root root 10 Oct 15 09:03 a.txt
$ usermod -d /srv/u4f1home -m u4f1
$ grep u4f1 /etc/passwd
u4f1:x:1801:1801::/srv/u4f1home:/bin/bash
$ ls -ld /home/u4f1 /srv/u4f1home
ls: cannot access '/home/u4f1': No such file or directory
drwxr-x--- 3 u4f1 u4f1 4096 Oct 15 09:03 /srv/u4f1home
$ ls -lR /srv/u4f1home
/srv/u4f1home:
total 4
-rw-r--r-- 1 root root 0 Oct 15 09:03 note.txt
drwxr-xr-x 2 root root 4096 Oct 15 09:03 proj
/srv/u4f1home/proj:
total 4
-rw-r--r-- 1 root root 10 Oct 15 09:03 a.txt
💡 要点:旧路径 /home/u4f1 已不存在(不是复制是搬移),子目录 proj 与文件原样出现在新路径,家目录权限位 drwxr-x--- 保持。⚠️ 注意 note.txt 等文件属主是 root(本例为 root 所建),usermod 搬家只搬不改属主,搬完应复核属主与配额。
3.6 -l:改登录名(家目录不变的现象)
-l(--login)只改登录名本身——passwd 第 1 字段;家目录路径、主组名、文件属主都不动:
usermod -l u4fnew u4f1
grep -E 'u4fnew|u4f1' /etc/passwd
id u4fnew
ls -ld /srv/u4f1home
grep -E '^u4f(1|new)' /etc/group
实测回显:
$ usermod -l u4fnew u4f1
$ grep -E 'u4fnew|u4f1' /etc/passwd
u4fnew:x:1801:1801::/srv/u4f1home:/bin/bash
$ id u4fnew
uid=1801(u4fnew) gid=1801(u4f1) groups=1801(u4f1),1012(u4fgrp1),1013(u4fgrp2),1014(u4fgrp3)
$ ls -ld /srv/u4f1home
drwxr-x--- 3 u4fnew u4f1 4096 Oct 15 09:03 /srv/u4f1home
$ grep -E '^u4f(1|new)' /etc/group
u4f1:x:1801:
💡 要点:
- 家目录仍是
/srv/u4f1home、主组仍叫 u4f1——改名是「最小动作」,如需一致要显式跟进usermod -d 新路径 -m与groupmod -n。 - ⚠️ 实测踩坑:改名不会同步
/etc/subuid、/etc/subgid里的旧名条目(Ubuntu 22.04 建号时自动分配 65536 宽的 subordinate 区间)。本例 u4f1 改名 u4fnew 后,subuid 里仍留u4f1:689824:65536旧条目,随后userdel u4fnew因名字对不上也删不掉它,形成残留,需要手工sed -i '/^旧名:/d' /etc/subuid /etc/subgid清理。 - 改名对已登录会话无影响,用户下次登录用新名。
3.7 -u:改 UID(文件属主随迁规则)
-u(--uid)改用户 ID。关键行为:家目录内属于旧 UID 的文件会被批量 chown 到新 UID,非该 UID 的文件保持不动。先以用户身份创建自有文件,再改 UID 对比:
useradd -m -s /bin/bash -u 1811 u4fown
su - u4fown -c 'touch ~/mine.txt && mkdir -p ~/data && echo mine > ~/data/m.txt'
ls -ln /home/u4fown
ls -ln /home/u4fown/data
touch /home/u4fown/rootfile.txt
usermod -u 1812 u4fown
id u4fown
ls -ln /home/u4fown
ls -ln /home/u4fown/data
实测回显:
$ useradd -m -s /bin/bash -u 1811 u4fown
$ su - u4fown -c 'touch ~/mine.txt && mkdir -p ~/data && echo mine > ~/data/m.txt'
$ ls -ln /home/u4fown
total 4
drwxrwxr-x 2 1811 1811 4096 Oct 15 09:04 data
-rw-rw-r-- 1 1811 1811 0 Oct 15 09:04 mine.txt
$ ls -ln /home/u4fown/data
total 4
-rw-rw-r-- 1 1811 1811 5 Oct 15 09:04 m.txt
$ touch /home/u4fown/rootfile.txt
$ usermod -u 1812 u4fown
$ id u4fown
uid=1812(u4fown) gid=1811(u4fown) groups=1811(u4fown),27(sudo)
$ ls -ln /home/u4fown
total 4
drwxrwxr-x 2 1812 1811 4096 Oct 15 09:04 data
-rw-rw-r-- 1 1812 1811 0 Oct 15 09:04 mine.txt
-rw-r--r-- 1 0 0 0 Oct 15 09:04 rootfile.txt
$ ls -ln /home/u4fown/data
total 4
-rw-rw-r-- 1 1812 1811 5 Oct 15 09:04 m.txt
💡 要点:
- 家目录内所有属主为 1811 的文件(含子目录深层
data/m.txt)全部随迁到 1812;root 建的rootfile.txt保持0 0不动——usermod 的 chown 是「旧 UID → 新 UID」的定向替换,不是整目录统一 chown。 - 家目录之外的属主文件不在此机制覆盖范围内(本组实测范围即家目录);跨目录改属主需运维自查:
find / -xdev -uid 旧UID列出后逐个chown。 - UID 冲突时直接报错(退出码 4,见 3.14),确需重复 UID 用
-o(见 3.9)。
3.8 -g:改主组(家目录组属主随迁)
-g(--gid)把主组换成另一个已存在的组,家目录内组属主为旧主组 GID 的文件同样随迁:
groupadd u4fgrp1
ls -ln /home/u4fown | head -3
usermod -g u4fgrp1 u4fown
id u4fown
ls -ln /home/u4fown
实测回显:
$ groupadd u4fgrp1
$ ls -ln /home/u4fown | head -3
total 4
drwxrwxr-x 2 1812 1811 4096 Oct 15 09:04 data
-rw-rw-r-- 1 1812 1811 0 Oct 15 09:04 mine.txt
$ usermod -g u4fgrp1 u4fown
$ id u4fown
uid=1812(u4fown) gid=1812(u4fgrp1) groups=1812(u4fgrp1),27(sudo)
$ ls -ln /home/u4fown
total 4
drwxrwxr-x 2 1812 1812 4096 Oct 15 09:04 data
-rw-rw-r-- 1 1812 1812 0 Oct 15 09:04 mine.txt
-rw-r--r-- 1 0 0 0 Oct 15 09:04 rootfile.txt
💡 要点:组属主 1811(原主组 u4fown)→ 1812(新主组 u4fgrp1),随迁规则与 -u 对称;root 文件同样不动。注意 id 输出的 groups 列表里原主组 u4fown 变成了普通成员组(附加组语义),若不想保留可再用 -G 精确重设。
3.9 -o:允许重复 UID
-o(--non-unique)配合 -u 允许把用户 UID 改成已被占用的值:
useradd -m -u 1813 u4froot
usermod -o -u 1812 u4froot
id u4froot
实测回显:
$ useradd -m -u 1813 u4froot
$ usermod -o -u 1812 u4froot
$ id u4froot
uid=1812(u4fown) gid=1812(u4fgrp1) groups=1812(u4fgrp1),27(sudo)
💡 要点:id u4froot 显示 uid=1812(u4fown)——按 UID 反查用户名时返回 passwd 中先出现的记录(u4fown 在前)。两个账号自此共享文件权限与审计身份,仅建议在历史系统兼容等特殊场景使用,安全基线扫描会将其列为告警项。
3.10 -c:改注释(GECOS)
-c(--comment)重写 passwd 第 5 字段:
usermod -c 'ops, oncall duty' u4fnew
grep u4fnew /etc/passwd
实测回显:
$ usermod -c 'ops, oncall duty' u4fnew
$ grep u4fnew /etc/passwd
u4fnew:x:1802:1013:ops, oncall duty:/srv/u4f1home:/bin/bash
💡 要点:整串含逗号空格时用引号包住;置空用 -c ''。等价的交互式工具是 chfn。
3.11 -e:改账号过期(含 -e '' 清除)与 -f 宽限
-e(--expiredate)改账号过期日,-e '' 清除过期(恢复永不过期);-f(--inactive)改密码过期后的宽限停用天数。用 chage -l 验证:
usermod -e 2027-06-30 -f 7 u4fnew
chage -l u4fnew | grep -E 'Account expires|Password inactive'
usermod -e 2027-06-30 u4fown
chage -l u4fown | grep 'Account expires'
usermod -e '' u4fown
chage -l u4fown | grep 'Account expires'
实测回显:
$ usermod -e 2027-06-30 -f 7 u4fnew
$ chage -l u4fnew | grep -E 'Account expires|Password inactive'
Password inactive : 7
Account expires : Jun 30, 2027
$ usermod -e 2027-06-30 u4fown
$ chage -l u4fown | grep 'Account expires'
Account expires : Jun 30, 2027
$ usermod -e '' u4fown
$ chage -l u4fown | grep 'Account expires'
Account expires : never
💡 要点:usermod -e/-f 与 chage -E/-f 写的是同一组 shadow 字段,互为替代;「临时账号转正」就用 usermod -e '' 清除过期。
3.12 -p:改密码哈希
-p(--password)直接写入新的 crypt 哈希,适用于密码重置脚本化:
usermod -p "$(openssl passwd -6 'q1w2e3r4')" u4fnew
passwd -S u4fnew
实测回显:
$ usermod -p "$(openssl passwd -6 'q1w2e3r4')" u4fnew
$ passwd -S u4fnew
u4fnew P 10/15/2026 0 99999 7 7
💡 要点:-p 要求加密串(见 useradd 篇 3.16 的哈希算法拓展表),明文会写坏;日常重置密码首选 passwd 用户名 或 echo '用户名:密码' | chpasswd。
3.13 -v/-V 与 -w/-W:subordinate UID/GID 管理
-v(--add-subuids)与 -w(--add-subgids)为用户追加 subordinate ID 区间(用户名字空间映射用,rootless 场景的 newuidmap 依赖它),-V/-W 为删除:
usermod -v 510000-510999 -w 510000-510999 u4fown
grep u4fown /etc/subuid
grep u4fown /etc/subgid
usermod -V 510000-510999 -W 510000-510999 u4fown
grep u4fown /etc/subuid
实测回显:
$ usermod -v 510000-510999 -w 510000-510999 u4fown
$ grep u4fown /etc/subuid
u4fown:755360:65536
u4fown:510000:1000
$ grep u4fown /etc/subgid
u4fown:755360:65536
u4fown:510000:1000
$ usermod -V 510000-510999 -W 510000-510999 u4fown
$ grep u4fown /etc/subuid
u4fown:755360:65536
💡 要点:Ubuntu 22.04 建号时会自动分配一段 65536 宽的 subordinate 区间(u4fown:755360:65536),-v 追加的是额外区间(510000:1000),-V 精确删除该区间后只剩默认段。该机制与 3.6 的「改名不同步 subuid 条目」坑互为印证。
3.14 报错行为与退出码实测
用户不存在、UID 冲突、改名冲突三类常见失败:
usermod u4fnoexist; echo rc=$?
useradd -m -u 1803 u4f2
usermod -u 1802 u4f2; echo rc=$?
usermod -l root u4f2; echo rc=$?
实测回显:
$ usermod u4fnoexist; echo rc=$?
usermod: user 'u4fnoexist' does not exist
rc=6
$ useradd -m -u 1803 u4f2
$ usermod -u 1802 u4f2; echo rc=$?
usermod: UID '1802' already exists
rc=4
$ usermod -l root u4f2; echo rc=$?
usermod: user 'root' already exists
rc=9
💡 要点:退出码 6 用户不存在、4 UID 已占用、9 目标登录名已存在;脚本按 $? 分支处理即可,无需解析报错文本。
3.15 其他低频参数速览
| 参数 | 语义(摘自 --help 实测原文) | 适用场景 |
|---|---|---|
-R, --root CHROOT_DIR | directory to chroot into | 救援环境下对目标盘的账号库做修改 |
-P, --prefix PREFIX_DIR | prefix directory where are located the /etc/* files | 根文件系统构建时重定位 /etc 前缀 |
-Z, --selinux-user SEUSER | new SELinux user mapping for the user account | SELinux 系统(Ubuntu 默认 AppArmor) |
-b, --badnames | allow bad names | 配合 -l 改成默认校验会拒绝的名字(风险同 useradd 篇 3.19) |
💡 说明:前三项需对应环境才有意义,本文未实测,语义以
usermod --help原文为准。
四、实战示例
4.1 场景一:授予 sudo 权限(-aG + 复核)
把运维人员加入 sudo 组(组已存在且有既有成员),完整复核链路:
getent group sudo
usermod -aG sudo u4fown
groups u4fown
getent group sudo
实测回显:
$ getent group sudo
sudo:x:27:u4c1,u4c2
$ usermod -aG sudo u4fown
$ groups u4fown
u4fown : u4fown sudo
$ getent group sudo
sudo:x:27:u4c1,u4c2,u4fown
要点:追加前后 getent group sudo 对比可确认「只加不移除」;⚠️ 已登录会话不会立刻获得新组身份,用户需退出重登(或 newgrp sudo 临时切换)后才生效。
4.2 场景二:锁定疑似失陷账号再解锁
安全处置标准动作:设密 → 锁定 → 复核 → 解锁:
echo 'u4f1:q1w2e3r4' | chpasswd
usermod -L u4f1
passwd -S u4f1
usermod -U u4f1
passwd -S u4f1
实测回显:
$ echo 'u4f1:q1w2e3r4' | chpasswd
$ usermod -L u4f1
$ passwd -S u4f1
u4f1 L 10/15/2026 0 99999 7 -1
$ usermod -U u4f1
$ passwd -S u4f1
u4f1 P 10/15/2026 0 99999 7 -1
要点:L → P 状态翻转即处置闭环;若要连 SSH 密钥登录一起禁用,再加 usermod -s /usr/sbin/nologin 并清空 ~/.ssh/authorized_keys。
4.3 场景三:家目录迁移到数据盘(-d -m + 复核)
usermod -d /srv/u4f1home -m u4f1
grep u4f1 /etc/passwd
ls -ld /home/u4f1 /srv/u4f1home
ls -lR /srv/u4f1home
实测回显:
$ usermod -d /srv/u4f1home -m u4f1
$ grep u4f1 /etc/passwd
u4f1:x:1801:1801::/srv/u4f1home:/bin/bash
$ ls -ld /home/u4f1 /srv/u4f1home
ls: cannot access '/home/u4f1': No such file or directory
drwxr-x--- 3 u4f1 u4f1 4096 Oct 15 09:03 /srv/u4f1home
$ ls -lR /srv/u4f1home
/srv/u4f1home:
total 4
-rw-r--r-- 1 root root 0 Oct 15 09:03 note.txt
drwxr-xr-x 2 root root 4096 Oct 15 09:03 proj
/srv/u4f1home/proj:
total 4
-rw-r--r-- 1 root root 10 Oct 15 09:03 a.txt
要点:迁移是搬移不是复制,旧路径消失;迁移后建议 chown -R 用户:组 新路径 统一属主(本例 root 所建文件属主未随迁)。
4.4 场景四:改 UID 且保留文件属主关系
应用账号 UID 需与备份/挂载约定对齐时:
usermod -u 1812 u4fown
id u4fown
ls -ln /home/u4fown
ls -ln /home/u4fown/data
实测回显:
$ usermod -u 1812 u4fown
$ id u4fown
uid=1812(u4fown) gid=1811(u4fown) groups=1811(u4fown),27(sudo)
$ ls -ln /home/u4fown
total 4
drwxrwxr-x 2 1812 1811 4096 Oct 15 09:04 data
-rw-rw-r-- 1 1812 1811 0 Oct 15 09:04 mine.txt
-rw-r--r-- 1 0 0 0 Oct 15 09:04 rootfile.txt
$ ls -ln /home/u4fown/data
total 4
-rw-rw-r-- 1 1812 1811 5 Oct 15 09:04 m.txt
要点:家目录内旧 UID 文件全部定向随迁(1811→1812),root 文件不动;组属主还在旧组(1811),下一步换主组见 4.5 或 3.8。
4.5 场景五:实测账号收尾清理(含两处隐藏残留)
userdel -r u4fown
userdel -r u4fnew
userdel -r u4f2
groupdel u4fgrp1
groupdel u4fgrp2
groupdel u4fgrp3
groupdel u4fown
sed -i '/^u4f1:/d' /etc/subuid
sed -i '/^u4f1:/d' /etc/subgid
grep -c u4f /etc/passwd
实测回显(节选,含关键提示):
$ userdel -r u4fown
userdel: group u4fown not removed because it is not the primary group of user u4fown.
$ groupdel u4fown
$ grep -c u4f /etc/passwd
0
要点:主组被 -g 改走之后,userdel 只删用户不删「与用户同名的旧组」,需手工 groupdel;改名产生的 /etc/subuid 旧条目同样要手工清(3.6 踩坑),这也是《userdel 命令详解与参数实测(Ubuntu 22.04)》篇的延伸阅读点。
五、注意事项与常见问题
Q1:usermod -G 执行后用户突然没权限了?
十有八九是漏了 -a。-G 的语义是「全量替换附加组列表」,替换后 /etc/group 里原组的成员字段被清空且无任何警告(3.2 实测)。恢复办法:把原有组加回去 usermod -aG 组1,组2 用户名。铁律:加组永远 -aG,重置才裸 -G,重置前先 groups 用户名 留底。
Q2:usermod -l 改了名,为什么家目录还是旧路径、主组还叫旧名?
-l 只改 passwd 第 1 字段的登录名,是最小改动(3.6 实测)。要路径一致需自行 usermod -d 新路径 -m;主组名一致用 groupmod -n 新组名 旧组名。另外改名不同步 /etc/subuid//etc/subgid,先改名后删除会残留旧名条目,需手工清理。
Q3:usermod -u 改完 UID,有些文件属主没变?
属主随迁只发生在「家目录内、属主恰为旧 UID」的文件上(3.7 实测:用户文件 1811→1812,root 文件原样)。家目录外散落的旧属主文件用 find / -xdev -uid 旧UID 排查后手工 chown。
Q4:usermod -L 锁定后,root 为什么还能 su 过去?
-L 锁的是「密码认证」(shadow 哈希前加 !,3.3 实测);root 执行 su 免密不受影响。SSH 等密码路径会被挡;若要求彻底禁登录,组合 -s /usr/sbin/nologin 与 -e 过期日。
Q5:改了组/sudo 权限,用户说没生效?
组身份在登录时写入会话,已打开的终端/SSH 不会热更新。让用户退出重登,或本会话内 newgrp 组名 临时切换验证。
Q6:usermod --version 报 unrecognized option?
shadow 4.8.1 的 usermod 没有 --version(2.3 实测,rc=2),查版本用 dpkg -l passwd。
Q7:报 user 'xxx' does not exist / UID 'n' already exists 怎么脚本化判断?
退出码分别是 6 与 4(3.14 实测),改名冲突为 9;直接 $? 分支,不要解析英文报错。
Q8:can not lock /etc/passwd 报错?
shadow 工具串行改库,通常有另一个 useradd/usermod/passwd/chpasswd 在跑或异常退出残留锁文件(/etc/passwd.lock 等)。确认无并发后删除残留锁文件重试。
Q9:生产固化建议?
① 加组必 -aG;② 改名后跟一轮「家目录、主组、subuid」三查;③ 改 UID/主组后 ls -ln 数字复核随迁结果;④ 锁号处置 passwd -S 留痕;⑤ 所有 usermod 后用 id、grep 用户名 /etc/passwd、getent group 组名 做三件套复核。
六、参考链接
- usermod(8) 手册(Ubuntu 22.04 jammy):https://manpages.ubuntu.com/manpages/jammy/en/man8/usermod.8.html
- useradd(8) 手册(配套建号工具):https://manpages.ubuntu.com/manpages/jammy/en/man8/useradd.8.html
- groupmod(8) 手册(主组改名配套):https://manpages.ubuntu.com/manpages/jammy/en/man8/groupmod.8.html
- login.defs(5) 手册(SUB_UID_MIN 等默认键):https://manpages.ubuntu.com/manpages/jammy/en/man5/login.defs.5.html
- chage(1) 手册(过期策略查看/修改):https://manpages.ubuntu.com/manpages/jammy/en/man1/chage.1.html
- shadow 工具集源码仓库:https://github.com/shadow-maint/shadow