Python:如何获取一个用户名的组ID(类似于id -Gn)

32

getpwname 只能获取一个 usernamegid

import pwd
myGroupId = pwd.getpwnam(username).pw_gid

getgroups 只能获取脚本用户的 groups

import os
myGroupIds = os.getgroups()

如何获取任意用户名的所有,就像id -Gn命令一样?

id -Gn `whoami`

至少我可以使用以下代码: from subprocess import check_output mygroups = check_output(['id', '-Gn', user]).split() - Ade YU
5个回答

36

以下内容适用于仅关注本地用户的情况,对于使用目录服务器(例如ldap)支持的sssd等内容不起作用。

#!/usr/bin/env python

import grp, pwd 

user = "myname"
groups = [g.gr_name for g in grp.getgrall() if user in g.gr_mem]
gid = pwd.getpwnam(user).pw_gid
groups.append(grp.getgrgid(gid).gr_name)
print groups

1
非常感谢,@gareth-a-lloyd。它有效。但我不明白为什么gid在前面的语句中没有列在groups中,或者为什么user not in grp.getgrgid(pwd.getpwnam(user).pw_gid).gr_name。很抱歉,我现在还没有足够的声望来投票支持你。 - Ade YU
grppwd是库模块,用于帮助解析/etc/group/etc/passwd。因此,生成给出groups的行是通过遍历/etc/group列表生成的。gid是用户的主要组ID,由/etc/passwd给出,然后使用该gid查找组名并将其添加到列表中。 - Gareth A. Lloyd
@gareth-a-lloyd 很有趣的是,user 没有列在它的主要组的 gr_mem 中。 - Ade YU
5
仅当用户本地存在于系统中时,此方法才有效,而在使用由LDAP支持的SSSD等工具时则无效。 - Jens Timmerman
1
@GarethA.Lloyd 我在评论区添加了一些有价值的信息,以丰富您的答案,因为它是一个相对受欢迎的答案,我和其他人显然找到了这里,但在排除了一段时间为什么没有显示所有组成员身份后感到失望。也许这可以帮助未来的灵魂少花时间分析问题所在。希望我没有打扰,但由于您的答案中没有任何描述,我认为值得添加一点 :) - Torxed
1
@Torxed 没关系,人们来到 SO 发帖的理由各不相同,8 年前的答案迟早需要更新。 - Gareth A. Lloyd

13
如果您想获取当前用户的组。
import os, grp
[grp.getgrgid(g).gr_name for g in os.getgroups()]

os.getgroups() 返回当前用户的gid列表。

grp.getgrgid(g) 返回有关组的详细信息。


2
这是最好的、最简洁的答案。 - cdjc
可以通过LDAP与sssd一起使用,但出于某些原因无法用于PAM会话。仍然是一个不错的选择。 - Torxed
在某些情况下可能会生成KeyError(不确定原因);可能需要处理该异常。 - undefined

9

我发现在系统中有非本地用户(例如ldap、sssd+ldap、freeIPA)时,让它正常工作的唯一方法是调用getgrouplist c函数(最终通过一些抽象调用id函数):

#!/usr/bin/python

import grp, pwd, os
from ctypes import *
from ctypes.util import find_library

libc = cdll.LoadLibrary(find_library('libc'))

getgrouplist = libc.getgrouplist
# 50 groups should be enough, if not, we'll repeat the request with the correct nr bellow
ngroups = 50
getgrouplist.argtypes = [c_char_p, c_uint, POINTER(c_uint * ngroups), POINTER(c_int)]
getgrouplist.restype = c_int32

grouplist = (c_uint * ngroups)()
ngrouplist = c_int(ngroups)

user = pwd.getpwuid(2540485)

ct = getgrouplist(bytes(user.pw_name, 'UTF-8'), user.pw_gid, byref(grouplist), byref(ngrouplist))

# if 50 groups was not enough this will be -1, try again
# luckily the last call put the correct number of groups in ngrouplist
if ct < 0:
    getgrouplist.argtypes = [c_char_p, c_uint, POINTER(c_uint *int(ngrouplist.value)), POINTER(c_int)]
    grouplist = (c_uint * int(ngrouplist.value))()
    ct = getgrouplist(user.pw_name, user.pw_gid, byref(grouplist), byref(ngrouplist))

for i in range(0, ct):
    gid = grouplist[i]
    print(grp.getgrgid(gid).gr_name)

1
为了使Python3更加友好,因为字节和字符串更加分离且自动编码不会发生。getgrouplist 应该将字节字符串作为其第一个参数,如下所示:getgrouplist(bytes(user.pw_name, 'UTF-8'), ...)。显然,在Python3中,xrange也是range。但这清除了从Python2到Python3的任何转换问题。 - Torxed
1
谢谢@Torxed,我已经将我的答案移植到Python3了。 - Jens Timmerman
代表所有来到这里的人 :) 感谢您多年后的更新! :) - Torxed

3
如果用户属于一个或多个组,其中几个组名称映射到相同的gid,则当运行id -Gn命令时的结果可能与发布的答案不同。例如,如果/etc/groups类似于此:
 % ypcat group | grep mygroup 
 mygroup:*:66485:user1,user2,user3,...
 mygroup1:*:66485:user101,user102,user103,...
 mygroup2:*:66485:user201,user202,user203,...
 ...

如果用户未列在mygroup中,而是列在mygroup<n>中,则id -Gn返回mygroup,但发布的答案返回mygroup<n>。 在我的环境中,由于UNIX组可以有数百或数千个用户,这似乎是一种常见的组管理策略,但我不知道每个组的用户限制以及为什么id -Gn总是返回mygroup。 尽管如此,使用以下代码,我与id -Gn匹配:
import pwd, grp    

def getgroups(user):
    gids = [g.gr_gid for g in grp.getgrall() if user in g.gr_mem]
    gid = pwd.getpwnam(user).pw_gid
    gids.append(grp.getgrgid(gid).gr_gid)
    return [grp.getgrgid(gid).gr_name for gid in gids]

格式化输出: print(*set(getgroups('user_name')))。请注意,在某些系统中,同一组可能会出现多次。对set的调用将进行过滤。 - Walker Hale IV

1
自Python 3.3版本以来:
import os
import pwd

uid = os.getuid()
user = pwd.getpwuid(uid)
gl = os.getgrouplist(user.pw_name, user.pw_gid)
print(gl)

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