User and group info

getgrnam#

Look up a Unix group by name and return its /etc/group record.

getgrnam wraps the C library’s getgrnam(3). Given a group name like "wheel" or "staff", it returns the matching record from the system’s group database — the name, the encrypted password placeholder, the numeric GID, and the list of member login names. Use it when you have a group name in hand and need the GID or the membership list; use getgrgid for the inverse lookup.

Synopsis#

my ($name, $passwd, $gid, $members) = getgrnam NAME
my $gid = getgrnam NAME

What you get back#

List context yields a four-element list:

my ($name, $passwd, $gid, $members) = getgrnam "wheel";

Index

Field

Meaning

0

$name

canonical group name (same as NAME on hit)

1

$passwd

group password field, typically "x" or empty

2

$gid

numeric group ID

3

$members

space-separated string of member login names

$members is a single scalar, not an array. Split it yourself when you want a list:

my @logins = split /\s+/, (getgrnam("wheel"))[3];

Scalar context yields the numeric GID (the “other thing”, since the lookup was by name):

my $gid = getgrnam "wheel";

No such group: list context returns the empty list; scalar context returns undef. Test scalar returns for definedness rather than truth — GID 0 (root) is a valid hit that is also false:

defined(my $gid = getgrnam $group) or die "no group '$group'";

Global state it touches#

None directly. getgrnam is a stateless lookup — unlike getgrent, it does not advance the group-database iterator, and setgrent / endgrent do not affect it. It does, however, share the underlying C library’s static result buffer with other getgr* calls on platforms without thread-safe variants; copy the fields you care about before calling another getgr* function.

Examples#

Resolve a group name to its GID:

my $gid = getgrnam "wheel";
defined $gid or die "no 'wheel' group on this system";
print "wheel GID = $gid\n";

List the members of a group:

my @fields = getgrnam "staff"
    or die "no 'staff' group";
my @members = split /\s+/, $fields[3];
print "staff has ", scalar(@members), " members: @members\n";

Use a group name to set the effective GID (requires privilege):

my $gid = getgrnam "video"
    // die "no 'video' group";
$) = "$gid $gid";                   # effective + supplementary

Check whether a user is listed as a group member. Note that the primary group (the user’s GID in /etc/passwd) is not in $members — check both:

sub in_group {
    my ($user, $group) = @_;
    my @g = getgrnam $group or return 0;
    return 1 if grep { $_ eq $user } split /\s+/, $g[3];
    my @u = getpwnam $user or return 0;
    return $u[3] == $g[2];          # primary group match
}

Object-oriented form via User::grent, which overrides the built-in with a by-name record:

use User::grent;
my $g = getgrnam "wheel";
printf "wheel: gid=%d members=%s\n", $g->gid, "@{$g->members}";

Edge cases#

  • Missing group: list context returns (), scalar returns undef. A bare if (getgrnam $g) is fine in list context but wrong in scalar context when the GID could be 0:

    if (defined(my $gid = getgrnam $g)) { ... }   # correct
    if (my $gid = getgrnam $g)           { ... }  # wrong for GID 0
    
  • Members is a string, not a list. Forgetting this and writing scalar @members = getgrnam $g (or indexing $members[0]) silently gives wrong results. Always split /\s+/ the fourth field.

  • Primary-group members are absent from the list. A user whose /etc/passwd GID matches the group is a member in the kernel’s eyes but will not appear in $members. Lookups that classify users by group must consult getpwnam too.

  • Password field is not a password. On every modern Linux the second field is "x" (shadow redirection) or empty. It is never the plaintext or hash of a group password. Do not rely on its format.

  • Case sensitivity: group names are case-sensitive on Linux. getgrnam "Wheel" does not find wheel.

  • Name with embedded whitespace or colon: the group database format does not allow either, so such names cannot exist; the lookup simply fails.

  • NSS backends: on systems configured with LDAP, SSSD, or other name-service switch modules, getgrnam consults those as well as /etc/group. Results therefore depend on /etc/nsswitch.conf and the configured backends, not on /etc/group alone.

  • Taint: the fields come from outside the program, so under -T they are tainted and must be laundered before use in sensitive operations.

  • Thread safety: pperl automatically substitutes the thread-safe getgrnam_r when the platform provides it. On platforms without it, concurrent getgr* calls across threads can clobber each other’s results.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • getgrgid — inverse lookup by numeric GID; reach for this when you have the GID and want the group name or member list

  • getgrent — iterate every group in the database when you do not know the name or GID in advance

  • setgrent — rewind the getgrent iterator to the start of the group database

  • endgrent — close the group-database file descriptor opened by iteration

  • getpwnam — the parallel call for the user database; use alongside getgrnam when you need to resolve a user’s primary group

  • User::grent — object-oriented wrapper that overrides getgrnam to return a record object with named accessors (name, passwd, gid, members) instead of a positional list