Làm thế nào để liệt kê tất cả người dùng trong một nhóm Linux?


273

Làm cách nào để liệt kê tất cả các thành viên của một nhóm trong Linux (và có thể các đơn vị khác)?


1
@ Silmari89, Không phải nếu anh ta muốn làm điều đó bằng lập trình.
Paul Tomblin

2
Tôi mới ở đây, tôi phát hiện ra rằng SF tồn tại ngay sau khi tôi đăng câu hỏi. Tôi đồng ý nó thuộc về SF hoặc SO.
user323094

5
Heh, tất nhiên, bây giờ nó có một giải pháp lập trình, vì vậy nó cũng có thể được biện minh ở đây.
Zed

Câu trả lời:


103

Thật không may, không có cách tốt, di động để làm điều này mà tôi biết. Nếu bạn cố phân tích / etc / nhóm, như những người khác đang đề xuất, bạn sẽ bỏ lỡ những người dùng có nhóm đó là nhóm chính của họ và bất kỳ ai đã được thêm vào nhóm đó thông qua một cơ chế khác ngoài các tệp phẳng UNIX (ví dụ LDAP, NIS, pam-pssql, v.v.).

Nếu tôi hoàn toàn phải tự làm điều này, có lẽ tôi sẽ làm điều ngược lại: sử dụng idđể có được các nhóm của mọi người dùng trên hệ thống (sẽ kéo tất cả các nguồn hiển thị cho NSS) và sử dụng Perl hoặc một cái gì đó tương tự để duy trì hàm băm bảng cho mỗi nhóm phát hiện ghi chú thành viên của người dùng đó.

Chỉnh sửa: Tất nhiên, điều này khiến bạn gặp phải một vấn đề tương tự: làm thế nào để có được danh sách mọi người dùng trên hệ thống. Vì vị trí của tôi chỉ sử dụng các tệp phẳng và LDAP, tôi chỉ có thể nhận danh sách từ cả hai vị trí, nhưng điều đó có thể đúng hoặc không đúng với môi trường của bạn.

Chỉnh sửa 2: Một người nào đó đã nhắc nhở tôi rằng getent passwdsẽ trả về danh sách tất cả người dùng trên hệ thống, bao gồm cả những người dùng từ LDAP / NIS / v.v., nhưng getent group vẫn sẽ nhớ những người dùng chỉ là thành viên thông qua mục nhập nhóm mặc định, vì vậy điều đó đã truyền cảm hứng cho tôi viết hack nhanh này.


#!/usr/bin/perl -T
#
# Lists members of all groups, or optionally just the group
# specified on the command line
#
# Copyright © 2010-2013 by Zed Pobre (zed@debian.org or zed@resonant.org)
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#

use strict; use warnings;

$ENV{"PATH"} = "/usr/bin:/bin";

my $wantedgroup = shift;

my %groupmembers;
my $usertext = `getent passwd`;

my @users = $usertext =~ /^([a-zA-Z0-9_-]+):/gm;

foreach my $userid (@users)
{
    my $usergrouptext = `id -Gn $userid`;
    my @grouplist = split(' ',$usergrouptext);

    foreach my $group (@grouplist)
    {
        $groupmembers{$group}->{$userid} = 1;
    }
}

if($wantedgroup)
{
    print_group_members($wantedgroup);
}
else
{
    foreach my $group (sort keys %groupmembers)
    {
        print "Group ",$group," has the following members:\n";
        print_group_members($group);
        print "\n";
    }
}

sub print_group_members
{
    my ($group) = @_;
    return unless $group;

    foreach my $member (sort keys %{$groupmembers{$group}})
    {
        print $member,"\n";
    }
}

3
Cảm ơn tất cả những người đã trả lời. Tôi đang tìm kiếm một cách di động để làm điều đó. Thông tin của bạn không phải là một cách dễ dàng và di động là hữu ích. Bạn cũng nêu chi tiết nhất về các tình huống giúp tôi hiểu vấn đề sâu sắc hơn, tôi đánh giá cao điều đó và tôi đã chọn câu trả lời của bạn là câu hỏi được chấp nhận.
dùng323094

2
Bạn có thể quyên tặng tập lệnh của mình cho nền tảng Linux không? Đó là năm 2012 và vẫn không có cách nào dễ dàng để có được các thành viên của một nhóm. Đó là điều làm tôi thất vọng về Linux.
mùa đông

6
Tôi đã thêm giấy phép giống như ISC cho bạn, tương thích với bất kỳ nhóm nào. Vui lòng gửi nó bất cứ nơi nào bạn nghĩ rằng nó sẽ được chấp nhận.
Zed

PAM không cung cấp thông tin tài khoản. Đó là Switch dịch vụ tên (nsswitch) thực hiện điều đó. Không phải tất cả 'cơ sở dữ liệu' (nhà cung cấp dữ liệu) sẽ hỗ trợ liệt kê nên getent passwdcó thể không hoạt động (ví dụ: nếu bạn đang sử dụng sssd).

Điểm hợp lệ về PAM vs NSS - Tôi đã thay đổi tham chiếu. Mặc dù tôi chưa sử dụng nó, sssd trông giống như một sự thay thế nscd thoạt nhìn chứ không phải là một nhà cung cấp dữ liệu thích hợp, và nếu nó bị hỏng getent passwdtôi sẽ coi đó là một lỗi trong sssd.
Zed

239
getent group <groupname>;

Nó có khả năng di động trên cả Linux và Solaris và nó hoạt động với các tệp nhóm / mật khẩu cục bộ, cấu hình NIS và LDAP.


43
Không hiển thị người dùng có nhóm làm nhóm mặc định của họ.
rlpowell


39
lid -g groupname | cut -f1 -d'(' 

7
Đây sẽ là cách tốt nhất, ngoại trừ nắp không có trong bản cài đặt Debian tiêu chuẩn. Trong Ubuntu, nó nằm trong gói tùy chọn libuser (nó không phải là gói trong id-utils có cùng tên). Tôi đã không tìm thấy nó trong Debian :(
user323094

Làm việc cho tôi trên Khoa học Linux
blong

trên Debian Wheezy, nắp cũng nằm trong gói libuser
Lluís

2
@JohnMcGehee RHEL nên được gọi là AustereLinux
goelakash

1
'-g' không phải là một lựa chọn cho tôi. Tôi đã cài đặt phiên bản id-utils 4.6 trên Ubuntu 16.04.
Wilson Bigss

25

Lệnh sau sẽ liệt kê tất cả người dùng thuộc về <your_group_name>, nhưng chỉ những người được quản lý bởi /etc/groupcơ sở dữ liệu, không phải LDAP, NIS, v.v. Nó cũng chỉ hoạt động cho các nhóm thứ cấp , nó sẽ không liệt kê những người dùng có nhóm đó được đặt làm chính vì nhóm chính là được lưu dưới dạng GID(ID nhóm số) trong tệp /etc/passwd.

grep <your_group_name> /etc/group

4
Bạn có thể grep trực tiếp vào tệp đó như grep <tên người dùng> / etc / nhóm. Nhanh hơn và ít chi phí hơn.
hộp sơn

16

Lệnh sau sẽ liệt kê tất cả người dùng thuộc về <your_group_name>, nhưng chỉ những người được quản lý bởi /etc/groupcơ sở dữ liệu, không phải LDAP, NIS, v.v. Nó cũng chỉ hoạt động cho các nhóm thứ cấp , nó sẽ không liệt kê những người dùng có nhóm đó được đặt làm chính vì nhóm chính là được lưu dưới dạng GID(ID nhóm số) trong tệp /etc/passwd.

awk -F: '/^groupname/ {print $4;}' /etc/group

7
Không hiển thị người dùng có nhóm làm nhóm mặc định của họ.
rlpowell

3
Không kiểm tra NIS và LDAP.
Paweł Nadolski

12

Tập lệnh shell sau sẽ lặp qua tất cả người dùng và chỉ in những tên người dùng thuộc về một nhóm nhất định:

#!/usr/bin/env bash
getent passwd | while IFS=: read name trash
do
    groups $name 2>/dev/null | cut -f2 -d: | grep -i -q -w "$1" && echo $name
done
true

Ví dụ sử dụng:

./script 'DOMAIN+Group Name'

Lưu ý: Giải pháp này sẽ kiểm tra NIS và LDAP cho người dùng và nhóm (không chỉ passwdgroupcác tệp). Nó cũng sẽ đưa vào tài khoản người dùng không được thêm vào một nhóm nhưng có nhóm được đặt làm nhóm chính.

Chỉnh sửa: Đã thêm sửa chữa cho kịch bản hiếm khi người dùng không thuộc nhóm có cùng tên.

Chỉnh sửa: được viết dưới dạng một kịch bản shell; được thêm vào trueđể thoát với 0trạng thái theo đề xuất của @Max Chernyak aka hakunin ; loại bỏ stderrđể bỏ qua những thỉnh thoảng groups: cannot find name for group ID xxxxxx.


Điều này thật tuyệt, và rất súc tích, nhưng nó in tên nhóm cũng như tên người dùng
andrew lorien 16/12/13

@andrewlorien, tôi hy vọng tôi đã khắc phục vấn đề bạn đề cập, nếu không xin vui lòng cung cấp thêm chi tiết.
Paweł Nadolski

Đoạn mã này là tốt, nhưng nó trả về mã thoát 1, lý do nào khiến nó không trả về 0? Có thể sửa chữa dễ dàng?
Tối đa

@hakunin, nó không trả về 0 khi tên người dùng cuối không thuộc nhóm. Bạn có thể nối "|| true" vào câu lệnh kết thúc để luôn nhận được 0 nếu đây là điều bạn muốn. Bạn có thể kiểm tra sau đó xuất ra để xem có người dùng nào được tìm thấy không.
Paweł Nadolski

@ PawełNadolski Tôi nhận ra, vì vậy cuối cùng đã thêm ; true. Trở về 0 là tốt để tránh vấp ngã hệ thống quản lý cấu hình của bạn (Chef, Ansible, v.v.).
Tối đa

7

Bạn có thể làm điều đó trong một dòng lệnh duy nhất:

cut -d: -f1,4 /etc/passwd | grep $(getent group <groupname> | cut -d: -f3) | cut -d: -f1

Lệnh trên liệt kê tất cả người dùng có tên nhóm là nhóm chính của họ

Nếu bạn cũng muốn liệt kê những người dùng có tên nhóm là nhóm phụ của họ, hãy sử dụng lệnh sau

getent group <groupname> | cut -d: -f4 |  tr ',' '\n'

1
Hãy cẩn thận: grepsẽ khớp với người dùng có tên chứa số nhóm (ví dụ: sc0ttsẽ được hiển thị như một phần của rootnhóm). Nếu đây là một vấn đề thì hãy sử dụng regex :$(getent group <groupname> | cut -d: -f3)\$(khớp với dấu chấm phẩy, id nhóm và cuối dòng). (Đừng thêm dấu ngoặc kép vào biểu thức chính quy hoặc bash phàn nàn.)
Scott Stevens

@ScottS Một hố rơi hợp pháp. Muốn giới thiệu các bước được đề xuất
Bhasta

3

chỉ một chút grep và tr:

$ grep ^$GROUP /etc/group | grep -o '[^:]*$' | tr ',' '\n'
user1
user2
user3

4
Không hiển thị người dùng có nhóm làm nhóm mặc định của họ.
rlpowell

3

Việc triển khai của Zed có lẽ nên được mở rộng để hoạt động trên một số UNIX chính khác.

Ai đó có quyền truy cập vào phần cứng Solaris hoặc HP-UX?; đã không kiểm tra những trường hợp đó.

#!/usr/bin/perl
#
# Lists members of all groups, or optionally just the group
# specified on the command line
#
# Date:         12/30/2013
# Author:       William H. McCloskey, Jr.
# Changes:      Added logic to detect host type & tailor subset of getent (OSX)
# Attribution:
#   The logic for this script was directly lifted from Zed Pobre's work.
#     See below for Copyright notice.
#   The idea to use dscl to emulate a subset of the now defunct getent on OSX
#     came from
#       http://zzamboni.org/\
#         brt/2008/01/21/how-to-emulate-unix-getent-with-macosxs-dscl/
#     with an example implementation lifted from
#       https://github.com/petere/getent-osx/blob/master/getent
#
# Copyright © 2010-2013 by Zed Pobre (zed@debian.org or zed@resonant.org)
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#

use strict; use warnings;

$ENV{"PATH"} = "/usr/bin:/bin";

# Only run on supported $os:
my $os;
($os)=(`uname -a` =~ /^([\w-]+)/);
unless ($os =~ /(HU-UX|SunOS|Linux|Darwin)/)
    {die "\$getent or equiv. does not exist:  Cannot run on $os\n";}

my $wantedgroup = shift;

my %groupmembers;

my @users;

# Acquire the list of @users based on what is available on this OS:
if ($os =~ /(SunOS|Linux|HP-UX)/) {
    #HP-UX & Solaris assumed to be like Linux; they have not been tested.
    my $usertext = `getent passwd`;
    @users = $usertext =~ /^([a-zA-Z0-9_-]+):/gm;
};
if ($os =~ /Darwin/) {
    @users = `dscl . -ls /Users`;
    chop @users;
}

# Now just do what Zed did - thanks Zed.
foreach my $userid (@users)
{
    my $usergrouptext = `id -Gn $userid`;
    my @grouplist = split(' ',$usergrouptext);

    foreach my $group (@grouplist)
    {
        $groupmembers{$group}->{$userid} = 1;
    }
}

if($wantedgroup)
{
    print_group_members($wantedgroup);
}
else
{
    foreach my $group (sort keys %groupmembers)
    {
        print "Group ",$group," has the following members:\n";
        print_group_members($group);
        print "\n";
    }
}

sub print_group_members
{
    my ($group) = @_;
    return unless $group;

    foreach my $member (sort keys %{$groupmembers{$group}})
    {
        print $member,"\n";
    }
}

Nếu có một cách tốt hơn để chia sẻ đề xuất này, xin vui lòng cho tôi biết; Tôi đã xem xét nhiều cách, và đây là những gì tôi nghĩ ra.


Xác nhận hoạt động trên Solaris 10 sau khi đổi id -Gnthành/usr/xpg4/bin/id -G -n
user667361

3

Tôi đã thực hiện điều này tương tự như mã perl ở trên, nhưng đã thay thế getent và id bằng các hàm perl gốc. Nó nhanh hơn nhiều và sẽ hoạt động trên các hương vị * nix khác nhau.

#!/usr/bin/env perl

use strict;
my $arg=shift;
my %groupMembers; # defining outside of function so that hash is only built once for multiple function calls

sub expandGroupMembers{
my $groupQuery=shift;
unless (%groupMembers){
    while (my($name,$pass,$uid,$gid,$quota,$comment,$gcos,$dir,$shell,$expire)=getpwent()) {
            my $primaryGroup=getgrgid($gid);
            $groupMembers{$primaryGroup}->{$name}=1;
    }
    while (my($gname,$gpasswd,$gid,$members)=getgrent()) {
            foreach my $member (split / /, $members){
                    $groupMembers{$gname}->{$member}=1;
            }
    }
}
my $membersConcat=join(",",sort keys %{$groupMembers{$groupQuery}});
return "$membersConcat" || "$groupQuery Does have any members";
}
print &expandGroupMembers($arg)."\n";

Một câu trả lời chỉ có liên kết là không xem xét một câu trả lời hay trên Stack Overflow. Vui lòng xem xét xóa điều này vì điều này không cung cấp câu trả lời cho câu hỏi hoặc giải thích thêm về cách câu trả lời này tốt hơn câu trả lời được chấp nhận. Hoặc bạn có thể thêm điều này như một bình luận một khi bạn có đủ danh tiếng. Bạn luôn có thể nhận xét về bài viết của riêng bạn.
Dipen Shah

2

Có một gói Debian và Ubuntu tiện dụng được gọi là ' thành viên ' cung cấp chức năng này:

Mô tả: Hiển thị các thành viên của một nhóm; theo mặc định, tất cả các thành viên là phần bổ sung của các nhóm: trong khi các nhóm hiển thị các nhóm mà người dùng được chỉ định thuộc về, các thành viên hiển thị người dùng thuộc về một nhóm được chỉ định.

... Bạn có thể yêu cầu các thành viên chính, thành viên phụ, cả hai trên một dòng, mỗi dòng trên các dòng riêng biệt.


Nếu op sử dụng openwrt thì sao?
dùng2284570

Thực sự tiện dụng, nhưng tiếc là không báo cáo thành viên nhóm miền.
simlev

1
getent group insert_group_name_here | awk -F ':' '{print $4}' | sed 's|,| |g'

Điều này trả về một danh sách người dùng được phân tách bằng dấu cách mà tôi đã sử dụng trong các tập lệnh để điền vào các mảng.

for i in $(getent group ftp | awk -F ':' '{print $4}' | sed 's|,| |g')
    do
        userarray+=("$i")
    done

hoặc là

userarray+=("$(getent group GROUPNAME | awk -F ':' '{print $4}' | sed 's|,| |g')")

0

Đây là tập lệnh trả về danh sách người dùng từ / etc / passwd và / etc / group, nó không kiểm tra NIS hoặc LDAP, nhưng nó cho thấy người dùng có nhóm là nhóm mặc định của họ được thử nghiệm trên Debian 4.7 và solaris 9

#!/bin/bash

MYGROUP="user"

# get the group ID
MYGID=`grep $MYGROUP /etc/group | cut -d ":" -f3`
if [[ $MYGID != "" ]]
then
  # get a newline-separated list of users from /etc/group 
  MYUSERS=`grep $MYGROUP /etc/group | cut -d ":" -f4| tr "," "\n"`
  # add a newline
  MYUSERS=$MYUSERS$'\n'
  # add the users whose default group is MYGROUP from /etc/passwod 
  MYUSERS=$MYUSERS`cat /etc/passwd |grep $MYGID | cut -d ":" -f1`

  #print the result as a newline-separated list with no duplicates (ready to pass into a bash FOR loop)
  printf '%s\n' $MYUSERS  | sort | uniq
fi

hoặc dưới dạng một lớp lót, bạn có thể cắt và dán thẳng từ đây (thay đổi tên nhóm trong biến đầu tiên)

MYGROUP="user";MYGID=`grep $MYGROUP /etc/group | cut -d ":" -f3`;printf '%s\n' `grep $MYGROUP /etc/group | cut -d ":" -f4| tr "," "\n"`$'\n'`cat /etc/passwd |grep $MYGID | cut -d ":" -f1`  | sort | uniq

0

Trong UNIX (trái ngược với GNU / Linux), có lệnh người nghe. Xem trang người đàn ông Solaris để biết người nghe .

Lưu ý rằng lệnh này là một phần của Dự án Gia truyền nguồn mở . Tôi cho rằng nó thiếu từ GNU / Linux vì RMS không tin vào các nhóm và quyền. :-)


1
Mặc dù liên kết này có thể trả lời câu hỏi, tốt hơn là bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
knuhol

NAME listusers - print a list of user logins SYNOPSIS listusers [-g groups] [-l logins] DESCRIPTION Listusers prints the name and the gecos information of all users known to the system, sorted by username. Valid options are: -g groups Only print the names of users that belong to the given group. Multiple groups are accepted if separated by commas. -l logins Print only user names that match logins. Multiple user names are accepted if separated by commas.
Alun Carr

Từ trang web Dự án gia truyền: Dự án Gia truyền cung cấp các triển khai truyền thống về các tiện ích Unix tiêu chuẩn. Trong nhiều trường hợp, chúng đã được lấy từ tài liệu Unix gốc được phát hành dưới dạng Nguồn mở của Caldera và Sun. Giao diện theo thông lệ truyền thống; nhìn chung chúng vẫn tương thích với System V, mặc dù các tiện ích mở rộng đã trở nên được sử dụng phổ biến theo thời gian đôi khi được cung cấp. Hầu hết các tiện ích cũng được bao gồm trong một biến thể nhằm mục đích tuân thủ POSIX.
Alun Carr

0

Đây là một kịch bản awk rất đơn giản có tính đến tất cả các cạm bẫy phổ biến được liệt kê trong các câu trả lời khác:

getent passwd | awk -F: -v group_name="wheel" '
  BEGIN {
    "getent group " group_name | getline groupline;
    if (!groupline) exit 1;
    split(groupline, groupdef, ":");
    guid = groupdef[3];
    split(groupdef[4], users, ",");
    for (k in users) print users[k]
  }
  $4 == guid {print $1}'

Tôi đang sử dụng tính năng này với thiết lập hỗ trợ ldap của mình, chạy trên mọi thứ với getent & awk tuân thủ tiêu chuẩn, bao gồm solaris 8+ và hpux.


0
getent group groupname | awk -F: '{print $4}' | tr , '\n'

Điều này có 3 phần:

1 - getent group groupnamehiển thị dòng của nhóm trong tệp "/ etc / group". Thay thế cho cat /etc/group | grep groupname.

2 - chỉ awkin các thành viên trong một dòng được phân tách bằng ','.

3 - trthay thế ',' bằng một dòng mới và in mỗi người dùng liên tiếp.

4 - Tùy chọn: Bạn cũng có thể sử dụng một đường ống khác với sort, nếu người dùng quá nhiều.

Trân trọng


0

Tôi nghĩ cách dễ nhất là các bước sau, bạn sẽ không cần cài đặt bất kỳ gói hoặc phần mềm nào:

  1. Trước tiên, bạn tìm ra GID của nhóm mà bạn muốn biết người dùng, có rất nhiều cách cho việc đó: cat / etc / group (cột cuối cùng là người dùng id GID) (người dùng là người thuộc về nhóm)

  2. Bây giờ bạn sẽ liệt kê tất cả người dùng trên tệp / etc / passwd, nhưng bạn sẽ áp dụng một số bộ lọc với các lệnh tiếp theo sau để chỉ nhận các thành viên của nhóm trước.

cut -d: -f1,4 / etc / passwd | grep GID (GID là số bạn nhận được từ bước 1)

Lệnh cắt sẽ chỉ chọn một số "cột" của tệp, tham số d đặt dấu phân cách ":" trong trường hợp này, tham số -f chọn "trường" (hoặc cột) để hiển thị 1 và 4 trong trường hợp ngoài (bật tệp / etc / passwd, cột 1 is là tên của người dùng và 4º là GID của nhóm mà người dùng thuộc về), để hoàn thiện | grep GID sẽ chỉ lọc nhóm (trên cột 4)) mà bạn đã chọn.


0

Đây là một lớp lót Python khác có tính đến tư cách thành viên nhóm mặc định của người dùng (từ /etc/passwd) cũng như từ cơ sở dữ liệu nhóm ( /etc/group)

python -c "import grp,pwd; print set(grp.getgrnam('mysupercoolgroup')[3]).union([u[0] for u in pwd.getpwall() if u.pw_gid == grp.getgrnam('mysupercoolgroup')[2]])"

-1

Tôi đã thử grep 'sample-group-name' /etc/group, nó sẽ liệt kê tất cả các thành viên của nhóm bạn đã chỉ định dựa trên ví dụ ở đây


1
Grepping đã /etc/groupcó ít nhất 3 câu trả lời khác, câu trả lời của bạn có giá trị gì đối với chúng? Ngoài ra, tất cả những câu trả lời khác đều có nhận xét rằng giải pháp đó chỉ hoạt động cho các nhóm thứ cấp và cũng không hoạt động đối với tài khoản được quản lý bởi LDAP, NIS, v.v.
David Ferenczy Rogožan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.