getent shadow 不能直接导出密码到期状态报表,因其输出为原始字段需解析,且“是否过期”须结合当前日期与第3、5字段计算,非root用户无法执行,即使root执行也无直观状态。

Linux 系统中,getent shadow 本身**不能直接导出密码到期状态报表**,因为 shadow 数据库默认仅 root 可读,且其字段含义需解析(如第 5、6、7 字段分别对应:密码最大使用天数、密码过期警告天数、密码失效天数),而“当前是否已过期”需结合系统日期与上次修改时间(第 3 字段)计算。
为什么 getent shadow 不适合直接批量导出到期状态
getent shadow 在非 root 用户下会失败;即使以 root 执行,输出是原始 shadow 行(如 alice:!!:19234:0:99999:7:::),不带可读状态(如“已过期”“7 天后到期”)。必须解析字段并做日期运算,awk 可承担此任务,但需配合系统当前日期和 /etc/shadow 权限控制逻辑。
安全前提:必须以 root 身份执行
读取 /etc/shadow 或调用 getent shadow 需 root 权限。建议:
- 用
sudo执行脚本,避免长期 root shell - 不将 shadow 内容写入临时明文文件(除非必要且严格权限控制)
- 优先用
getent shadow(兼容 LDAP/NIS),而非直接读/etc/shadow
实用 awk 脚本:生成可读的密码到期状态报表
以下脚本以 root 运行,输出含用户名、上次改密日期、到期剩余天数、当前状态(正常/警告/已过期/永不过期):
sudo getent shadow | awk -F: '
BEGIN {
"date +%s" | getline now_sec
close("date +%s")
}
$2 != "*" && $2 != "!" && $2 != "" { # 过滤掉禁用/锁定账户
lastchg = $3 == "" ? 0 : $3
maxdays = $5 == "" ? 99999 : $5
warndays = $6 == "" ? 7 : $6
if (lastchg == 0) {
status = "never set"
remain = "N/A"
} else {
expire_sec = (lastchg + maxdays) * 86400
remain_days = int((expire_sec - now_sec) / 86400)
if (remain_days = 0) {
status = "WARNING"
} else {
status = "OK"
}
remain = remain_days
}
printf "%-12s %s %8s %s\n", $1, \
(lastchg==0?"never":strftime("%Y-%m-%d", lastchg*86400)), \
remain, status
}' | column -t
说明:
-
$2 != "*" && $2 != "!":跳过被锁定或无密码账户 -
strftime()将上次修改时间(自 1970-01-01 起的天数)转为易读日期 - 状态判断基于系统当前秒级时间(
date +%s),结果更准确 -
column -t对齐输出,提升可读性
导出为 CSV 供 Excel 分析
只需替换 printf 格式并去掉 column:
sudo getent shadow | awk -F: '
BEGIN {"date +%s"|getline now; close("date +%s")}
$2 != "*" && $2 != "!" && $2 != "" {
last=$3; max=$5? $5 : 99999; warn=$6? $6 : 7
expire = (last+max)*86400
remain = int((expire-now)/86400)
status = remain /tmp/passwd_expiry_report.csv
该 CSV 可直接用 Excel 或 LibreOffice 打开,按 status 或 remain 排序筛选高风险账户。
不复杂但容易忽略的是:密码策略受 PAM 模块(如 pam_pwquality)、/etc/login.defs 全局设置及用户单独配置共同影响,脚本只反映 shadow 中记录的数值状态,不替代实际登录测试或审计工具(如 aide 或商业 IAM 平台)。











