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 改变后文件属主随迁规则与退出码。

Linux命令Linux系统UbuntuUbuntu 22.04命令行用户权限2026/10/15

usermod 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 usermod 的每一个常用参数——-aG 追加附加组与漏 -a 的覆盖风险、-L/-U 锁定解锁、-s 改 shell、-d -m 搬家、-l 改名、-u/-g 改 UID 与主组、-o 重复 UID、-c/-e/-f/-p 属性修改、-v/-w subordinate 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 改过期
chfnGECOS 注释(姓名/办公室/电话)交互式改注释
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

💡 要点:

  1. 覆盖前 u4f1 的附加组是 u4fgrp1、u4fgrp2;漏 -a 的 -G u4fgrp3 执行后,/etc/group 里 u4fgrp1、u4fgrp2 的成员字段被清空(u4fgrp1:x:1012:),只剩 u4fgrp3 有成员 u4f1——用户悄悄丢了 sudo 之类的组权限,且命令不报任何警告。
  2. 主组 u4f1(gid 1801)不受 -G 影响,主组只随 -g 变。
  3. 经验法则:给已有用户加组永远写 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

💡 要点:

  1. passwd -S 第二列:P 有效密码、L 已锁定;shadow 原文可见哈希前多了 !(u4f1:!$y$...),这就是锁定的实现——顺带确认本机 chpasswd 默认算法是 yescrypt($y$)。
  2. -L 只挡「密码认证」;root 用 su 切换该用户不需要密码,因此root 侧 su 不受 -L 影响,锁定的作用对象是 SSH/登录管理器等密码认证路径。要求「彻底不可登录」应改 shell 为 nologin 或配合 -e 过期。
  3. 对无密码用户执行 -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:

💡 要点:

  1. 家目录仍是 /srv/u4f1home、主组仍叫 u4f1——改名是「最小动作」,如需一致要显式跟进 usermod -d 新路径 -m 与 groupmod -n。
  2. ⚠️ 实测踩坑:改名不会同步 /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. 改名对已登录会话无影响,用户下次登录用新名。

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

💡 要点:

  1. 家目录内所有属主为 1811 的文件(含子目录深层 data/m.txt)全部随迁到 1812;root 建的 rootfile.txt 保持 0 0 不动——usermod 的 chown 是「旧 UID → 新 UID」的定向替换,不是整目录统一 chown。
  2. 家目录之外的属主文件不在此机制覆盖范围内(本组实测范围即家目录);跨目录改属主需运维自查:find / -xdev -uid 旧UID 列出后逐个 chown。
  3. 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_DIRdirectory to chroot into救援环境下对目标盘的账号库做修改
-P, --prefix PREFIX_DIRprefix directory where are located the /etc/* files根文件系统构建时重定位 /etc 前缀
-Z, --selinux-user SEUSERnew SELinux user mapping for the user accountSELinux 系统(Ubuntu 默认 AppArmor)
-b, --badnamesallow 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 组名 做三件套复核。

六、参考链接