在Linux/POSIX系统中,获取用户的全名最简单的方法是什么?

46

我可以通过grep命令在/etc/passwd中查找,但那似乎很繁琐。'finger'未安装,我想避免使用它。由于这是一个程序,因此最好有一些命令可以让您直接访问用户信息。

10个回答

65
你没有指定编程语言,所以我会假设你想要使用shell;这是适用于Posix shell的答案。这个过程分两步:获取适当的记录,然后从该记录中获取所需字段。首先,获取帐户记录是通过查询passwd表完成的。
$ user_name=foo
$ user_record="$(getent passwd $user_name)"
$ echo "$user_record"
foo:x:1023:1025:Fred Nurk,,,:/home/foo:/bin/bash

由于历史原因,用户的全名被记录在一个称为“GECOS”字段的字段中;为了使事情更加复杂,这个字段通常有其自己的结构,其中完整姓名只是几个可选子字段之一。因此,任何想要从帐户记录中获取完整姓名的内容都需要解析这两个层次。

$ user_record="$(getent passwd $user_name)"
$ user_gecos_field="$(echo "$user_record" | cut -d ':' -f 5)"
$ user_full_name="$(echo "$user_gecos_field" | cut -d ',' -f 1)"
$ echo "$user_full_name"
Fred Nurk

你的编程语言很可能有一个库函数可以用更少的步骤来完成这个任务。在C语言中,你可以使用“getpwnam”函数,然后解析GECOS字段。


24
歇斯底里的葡萄干? - dat
2
对我没用,但这个可以:getent passwd | grep "$USER" | cut -d":" -f5 | cut -d"," -f1 - Dean Rather
2
使用grep "^$USER:"或getent passwd $USER来不匹配包含当前用户名称的所有用户名。 - nvrandow
11
"历史性的葡萄干" 的意思是荒唐可笑或无聊的事情。请不要编辑这个原文! - MestreLion
因为答案的质量而点赞,同时我也喜欢“历史葡萄干”。 - Chris Parker
很棒的答案。根据你的回答,这是另一个适合插入到例如/etc/profile.d中的一行代码: export FULL_USER_NAME="$(getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1)" - Neil Stephens

33

在现代glibc系统上,使用此命令:

getent passwd "username" | cut -d ':' -f 5

这将获取指定用户的passwd条目,与底层NSS模块无关。

阅读getent的手册页面


如果您已经在编程,可以使用getpwnam() C函数:

struct passwd *getpwnam(const char *name);
passwd 结构体有一个 pw_gecos 成员,应该包含用户的全名。
阅读 getpwnam() 的手册页
请注意,许多系统将此字段用于超出用户全名的用途。最常见的约定是在字段内使用逗号 (,) 作为分隔符,并将用户真实姓名放在第一位。

3
通常获取用户真实姓名的命令是 getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1 - jpyams
1
$USER 周围加上双引号,以防它包含特殊字符,并且在 :, 周围不加引号:getent passwd "$USER" | cut -d: -f5 | cut -d, -f1 - Alexander
无法正常工作 getent passwd "${USER}" | cut -d: -f5 在非sudo环境下会返回 ,,,。编辑:我认为是因为创建的用户没有名字。 - MaXi32

11

结合其他答案,在最小的Debian/Ubuntu安装上进行测试:

getent passwd "$USER" | cut -d ':' -f 5 | cut -d ',' -f 1

没有实际的理由去调用一个子shell来执行 whoami 命令,你可以直接使用任何用户名作为参数。如果一定要使用子shell,请不要使用反引号,而是使用 $()。但在这种情况下,使用 "$USER" 更加合适。 - MestreLion

9

如果您想用C语言实现此操作,请尝试以下方法:

#include <sys/types.h>
#include <pwd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

/* Get full name of a user, given their username. Return 0 for not found,
   -1 for error, or 1 for success. Copy name to `fullname`, but only up
   to max-1 chars (max includes trailing '\0'). Note that if the GECOS
   field contains commas, only up to to (but not including) the first comma
   is copied, since the commas are a convention to add more than just the
   name into the field, e.g., room number, phone number, etc. */
static int getfullname(const char *username, char *fullname, size_t max)
{
    struct passwd *p;
    size_t n;

    errno = 0;
    p = getpwnam(username);
    if (p == NULL && errno == 0)
        return 0;
    if (p == NULL)
        return -1;
    if (max == 0)
        return 1;
    n = strcspn(p->pw_gecos, ",");
    if (n > max - 1)
        n = max - 1;
    memcpy(fullname, p->pw_gecos, n);
    fullname[n] = '\0';
    return 1;
}

int main(int argc, char **argv)
{
    int i;
    int ret;
    char fullname[1024];

    for (i = 1; i < argc; ++i) {
        ret = getfullname(argv[i], fullname, sizeof fullname);
        if (ret == -1)
            printf("ERROR: %s: %s\n", argv[i], strerror(errno));
        else if (ret == 0)
            printf("UNKONWN: %s\n", argv[i]);
        else
            printf("%s: %s\n", argv[i], fullname);
    }
    return 0;
}

8

试试这个:

getent passwd eutl420 | awk -F':' '{gsub(",", "",$5); print $5}'

4

前两个答案可以合并成一行:

getent passwd <username> | cut -d ':' -f 5 | cut -d ',' -f 1

2

我的代码在bash和ksh中可用,但在dash或旧版Bourne shell中不可用。它也读取其他字段,以防您需要它们。

IFS=: read user x uid gid gecos hm sh < <( getent passwd $USER )
name=${gecos%%,*}
echo "$name"

您也可以扫描整个 /etc/passwd 文件。这在简单的 Bourne shell 中可以工作,使用一个进程,但在 LDAP 等情况下效果不佳。
while IFS=: read user x uid gid gecos hm sh; do
  name=${gecos%%,*}
  [ $uid -ge 1000 -a $uid -lt 60000 ] && echo "$name"
done < /etc/passwd

另一方面,使用工具是有好处的。C语言也很不错。

0

在Linux上将全名存入变量的方法是:

u_id=`id -u`
uname=`awk -F: -vid=$u_id '{if ($3 == id) print $5}' /etc/passwd`

然后只需简单地使用该变量,例如:$ echo $uname


-1

第一步:

$ user_name=sshd
$ awk -F: "\$1 == \"$user_name\" { print \$5 }" /etc/passwd
Secure Shell Daemon

然而,passwd数据库支持在gecos中使用特殊字符'&',应该用用户名的大写值替换它:

$ user_name=operator
$ awk -F: "\$1 == \"$user_name\" { print \$5 }" /etc/passwd
System &

这里的大多数答案(除了指纹解决方案)都没有尊重 &。 如果您想支持此情况,则需要一个更复杂的脚本。

第二个方案:

$ user_name=operator
$ awk -F: "\$1 == \"$user_name\" { u=\$1; sub(/./, toupper(substr(u,1,1)), u);
    gsub(/&/, u, \$5); print \$5 }" /etc/passwd
System Operator

-2

老牌的finger命令也可能有所帮助 :-)

finger $USER |head -n1 |cut -d : -f3

2
OP已经提到,在你发布这个答案之前至少一年没有安装指纹了 ;) - Scott Rowley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接