如何列出 Linux 机器上活跃用户的邮件地址?

如何列出 Linux 机器上活跃用户的邮件地址?

我想获取所有允许登录的用户的邮件地址列表。我该怎么做?

我已经/etc/passwd使用GECOS 字段,即通过。sudo chfn some_user -o [email protected]

这可以是使用 awk 完成

awk -F : '{print $5}' /etc/passwd | awk -F , '{print $5}'

但是,我想排除帐户已过期的用户。

用户过期信息存储在 中/etc/shadow。这里有一个 Python 模块速度,但它已被弃用,并且它的后继者似乎无法检查帐户是否仍然有效。

该命令chage -l my_user显示到期日期,但即使影子文件对所有人都是可读的,也需要 root 权限才能获取其他用户的信息。

除了有效期之外,还有什么需要我注意的吗?

答案1

我找到了一种虽然有点脆弱但还算有效的方法:

join -t: /etc/shadow /etc/passwd | awk -F : '$8==""{print $13}'  | awk -F , '{print $5}'

警告:上述命令可能不会在每种情况下都执行正确的操作!

它使用来自这个答案打印出 GECOS 信息并将其与 join 合并,这样我们就可以同时使用 passwd 和 shadow 中的信息:行在第一列匹配(-t:指定:用作分隔符),因此使用用户名匹配文件。在 join 文件中,第 13 列是 GECOS 信息,只有当第 8 列为空时才会打印。第 8 列包含帐户到期信息。

陷阱:

  • 如果影子文件和密码文件的排序方式不同,可能会缺少某些行并打印警告:join: /etc/shadow:38: is not sorted: [...]。我还没有想出如何在没有临时文件的情况下解决这个问题:join 的手册页建议在将文件传递给 join 之前对其进行排序,但显然使用 stdin 只能传递一个文件,因此需要临时文件。
  • 帐户到期信息实际上并不与今天的日期进行比较。它只是过滤所有设置了到期日期的行。就我而言,所有活跃帐户都是无限制的,永不过期,已停用的帐户的到期日期设置为 1。因此,这个解决方案对我来说已经足够好了。
  • 我们不检查有效的登录 shell。不确定这是否是应该做的。

答案2

ChatGPT 为我编写了一个合适的脚本,其效果比 bash 单行脚本更好:

#!/bin/bash

# Print email addresses of all users on this machine.
# Email addresses are stored in the GECOS field in the of the passwd file. Accounts which are
# expired are ignored.
#
# The script might need to be run as root, depending on whether the /etc/shadow file is readable by
# your user or not.
#
# This script has been written by ChatGPT (and then fixed by a human).


set -e  # abort script on first error


is_account_expired() {
    local expire_date=$(grep "^$1:" /etc/shadow | cut -d ':' -f 8)
    local today=$(date +%s)
    if [[ -z $expire_date || $expire_date -ge $today ]]; then
        return 1  # Account is not expired
    else
        return 0  # Account is expired
    fi
}

while IFS=':' read -r username _; do
    if ! grep -q "^$username:" /etc/shadow; then
        continue  # Skip if account does not exist in shadow file
    fi
    if ! is_account_expired "$username"; then
        # Extract email from GECOS field
        email=$(getent passwd "$username" | cut -d ':' -f 5 | awk -F',' '{print $5}')
        # Print email if not expired and not empty
        if [ -n "$email" ]; then
            echo "$email"
        fi
    fi
done < /etc/passwd

相关内容