You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux脚本中可靠区分服务账户与普通用户账户?

更严谨区分Linux服务账户与普通用户的脚本实现

你用登录shell判断账户类型的思路方向是对的,但确实存在不够严谨的地方——比如有些特殊场景下,普通用户可能被管理员设置成/bin/false禁止登录,而像postgres这类服务账户默认是有可登录shell的,只靠shell判断就会出现误判。下面给你几个更权威、适合脚本自动化的判断方式:

1. 基于UID范围判断(最权威的标准)

Linux系统对账户UID有默认的划分规则:

  • 系统/服务账户的UID通常小于UID_MIN(多数发行版默认是1000,部分老版本如RHEL是500)
  • 普通用户的UID在UID_MIN到UID_MAX之间

这个规则是由/etc/login.defs文件定义的,我们可以直接读取这个文件的配置来做判断,适配不同发行版:

# 从login.defs获取普通用户UID的范围
UID_MIN=$(grep "^UID_MIN" /etc/login.defs | awk '{print $2}')
UID_MAX=$(grep "^UID_MAX" /etc/login.defs | awk '{print $2}')

# 遍历/etc/passwd判断账户类型
while IFS=":" read -r username passwd uid gid gecos home shell; do
    if [[ $uid -lt $UID_MIN ]]; then
        utype="Service"
    elif [[ $uid -ge $UID_MIN && $uid -le $UID_MAX ]]; then
        utype="User"
    else
        # UID超过UID_MAX的,通常是自定义系统账户,也归为Service
        utype="Service"
    fi
    # 打印账户详情
    echo "Username: $username, UID: $uid, Home: $home, Shell: $shell, Type: $utype"
done < /etc/passwd

2. 结合UID与登录shell的双重判断(兼顾准确性与场景)

如果担心单纯UID判断会把一些特殊普通用户(比如UID小于1000的管理员账户)误判,可以结合登录shell做双重验证:

UID_MIN=$(grep "^UID_MIN" /etc/login.defs | awk '{print $2}')
# 定义服务账户常见的登录shell列表
SERVICE_SHELLS=("/sbin/nologin" "/usr/sbin/nologin" "/bin/false" "/usr/bin/false")

while IFS=":" read -r username passwd uid gid gecos home shell; do
    utype="User"
    # 先判断UID是否属于系统账户范围
    if [[ $uid -lt $UID_MIN ]]; then
        utype="Service"
    else
        # 再检查普通用户的shell是否是服务类shell(避免普通用户被设置成不可登录)
        for s in "${SERVICE_SHELLS[@]}"; do
            if [[ $shell == "$s" ]]; then
                utype="Service"
                break
            fi
        done
    fi
    echo "Username: $username, UID: $uid, Shell: $shell, Type: $utype"
done < /etc/passwd

3. 修正你现有正则的问题

你的现有正则表达式reg=".*/[nologin|false]"存在语法错误:[]是字符集匹配,这里应该用分组()来匹配完整字符串,或者直接精确匹配更稳妥:

# 写法一:正则匹配结尾为nologin或false的shell
reg=".*(nologin|false)$"
if [[ "$lshell" =~ $reg ]]; then
    utype="Service"
fi

# 写法二:精确匹配,避免误判包含这些字符串的其他shell
if [[ "$lshell" == */nologin || "$lshell" == */false ]]; then
    utype="Service"
fi

补充:主目录辅助判断

服务账户的主目录通常不是/home/下的用户目录,而是系统目录(比如/var/lib/mysql、/usr/sbin),可以作为辅助判断条件,但注意这不是绝对标准,只能用来优化判断准确性:

if [[ $home != /home/* ]]; then
    # 进一步倾向于判定为服务账户
    utype="Service"
fi

内容的提问来源于stack exchange,提问作者dig_123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:27:40