passwd -S 命令的输出通常包含 7 个字段:用户名、密码状态(P/L/NP)、最后修改日期、最小有效期、最大有效期、过期前警告天数,以及过期后的宽限期。通过第 2 个字段,可以快速判断账户是否被锁定(L)或未设置密码(NP);再结合第 3 和第 5 个字段,还能进一步推算密码的实际过期时间。这种方式特别适合 Linux 系统日常巡检、批量排查和快速筛选密码过期状态。

/etc/shadow 最准确,但需要手动计算日期;使用 chage -l 最直观,适合人工查看,不过执行速度较慢;而 passwd -S 更适合批量筛查和自动化巡检。三种方法对权限要求相同,都需要使用 sudo 或 root 权限。
怎么用 chage -l 批量查所有用户
chage -l 的输出会直接显示自然语言日期(例如 Password expires : Aug 12, 2026),可读性非常好,适合快速理解单个用户的密码到期时间。不过,它需要针对每个用户分别调用一次系统命令,用户数量较多时,整体执行会明显变慢。
实际操作建议:
- 只检查非系统账户:可使用
getent passwd | awk -F: '$3 >= 1000 {print $1}'过滤 UID ≥1000 的普通用户,避免把root、daemon等系统账号一并扫描 - 加上
2>/dev/null屏蔽权限不足或解析失败时的报错(例如某些 LDAP 用户无法被本地chage正常识别) - 不要使用
for user in $(cat /etc/passwd | cut -d: -f1)—— 这种写法不仅会把nobody、systemd-network等账户全部扫进去,而且遇到带空格或特殊字符的用户名时容易出错
推荐一行命令:
sudo getent passwd | awk -F: '$3 >= 1000 {print $1}' | while read u; do echo -n "$u: "; sudo chage -l "$u" 2>/dev/null | grep 'Password expires' | cut -d: -f2; done | sed 's/^ *//'
为什么 passwd -S 更适合巡检筛选
passwd -S 输出字段固定、结构紧凑,没有多行文本,也不依赖本地化日期格式,因此更适合脚本解析和自动化检查。关键字段主要是第 3 列(最后一次修改密码的日期)和第 5 列(密码最大有效期天数),将两者相加后,就可以计算出密码的到期时间。
常见陷阱:
- 第 3 列采用 MM/DD/YYYY 格式(并非 YYYY-MM-DD),虽然
date -d一般可以识别,但如果直接用awk拆分处理,容易因为格式问题出现解析错误 - 当状态码为
L(锁定)或NP(无密码)时,后面的日期字段可能为空或无效,因此脚本处理前应先过滤这些账户 - 服务账户(例如
mysql、redis)通常会设置PASS_MAX_DAYS 99999,所以passwd -S中常显示为99999。但实际密码策略还需要结合/etc/login.defs里的PASS_MAX_DAYS配置一起判断
如何快速筛选未来 7 天内即将过期的用户?
sudo passwd -S | awk '$2 == "P" && $4 > 0 && $5 > 0 {cmd = "date -d "" $3 " + " $5 " days" +%Y-%m-%d 2>/dev/null"; cmd | getline exp; close(cmd); if (exp != "" && exp <= "2026-07-16") print $1, exp}'
直接解析 /etc/shadow 字段要注意什么
/etc/shadow 的第 3 列表示自 epoch 起到上次修改密码为止的天数(如 19823),第 5 列表示密码最大有效期天数(如 90),两者相加后即可得到密码过期日对应的 epoch 天数。不过,第 8 列(账户绝对过期日期)的优先级更高——如果该字段非空且早于当前日期,那么账户已经彻底失效,此时即使密码是否过期,也不会再影响登录结果。
关键细节:
- 第 3 列为
0表示“密码从未设置”,并不代表“刚刚修改过密码”,此时第 5 列通常没有实际参考意义 - 第 5 列为
99999或为空(即::)通常表示密码不过期,但仍建议结合/etc/login.defs中全局的PASS_MAX_DAYS配置一起确认 date -d "1970-01-01 +19823 days"在部分旧版系统(glibc < 2.32)上可能不支持较大的数字计算,遇到这种情况,建议使用perl -e 'print scalar localtime(19823*86400)."n"'作为替代方案
哪些用户根本不会走 shadow 密码过期逻辑
LDAP、AD、SSSD 或 Samba 用户并不依赖本地/etc/shadow,这类账户的密码过期策略通常由远程目录服务统一控制。因此,chage 和 passwd -S 对这些用户可能会返回 password status is unknown,或者直接执行失败。
识别方式:
getent shadow username返回为空,但getent passwd username能查到结果 → 这通常说明该用户很可能来自远程认证源id username显示的 GID/UID 来自非本地来源(例如domain users)authconfig --test | grep -i ldap或sssd --version可以帮助确认系统是否启用了集中认证
ldapsearch、ipa user-show 或 smbstatus 等工具,不能只依赖本地命令进行简单扫描。