--- name: getgrent status: documented categories: ["User and group info"] --- ```{index} single: getgrent; Perl built-in ``` *[User and group info](../perlfunc-by-category)* # getgrent Read the next entry from the system group database. `getgrent` walks the host's group database one entry at a time, the way a plain loop over `/etc/group` would read it line by line, and returns a Perl-shaped view of each record. It is the iterator form of the group lookups — use it when you want every group, or every group matching some predicate. For single-entry lookup by name or gid, reach for [`getgrnam`](getgrnam) or [`getgrgid`](getgrgid) instead. A first call to `getgrent` implicitly opens the database. Iteration continues across further calls until the database is exhausted, at which point `getgrent` returns the empty list (or [`undef`](undef) in scalar context). Call [`setgrent`](setgrent) to rewind to the start, or [`endgrent`](endgrent) to close the database and free any resources the C library is holding. ## Synopsis ```perl my ($name, $passwd, $gid, $members) = getgrent; my $name = getgrent; # scalar context ``` ## What you get back In **list context**, a four-element list — one entry per group: | Index | Field | Meaning | |-------|-----------|-----------------------------------------------------------| | 0 | `$name` | Group name (e.g. `"wheel"`) | | 1 | `$passwd` | Group password, typically `"x"` on shadow-password hosts | | 2 | `$gid` | Numeric group id | | 3 | `$members`| Space-separated string of member login names | When iteration runs off the end, the return is the empty list. If you write `if (my @gr = getgrent)` the loop terminates cleanly on end-of-database. In **scalar context**, `getgrent` returns just `$name`. When the database is exhausted, it returns [`undef`](undef) — which is the signal most scripts test against to end a `while` loop. `$members` is a plain string, not an array. Split it on whitespace when you need the list: ```perl my @logins = split ' ', $members; ``` ## Global state it touches `getgrent` keeps **per-process iteration state** inside the C library (conceptually a file position inside the group database). Two calls in the same process share that state; a nested loop that calls `getgrent` inside another `getgrent` loop will interleave records and miss most of them. Serialise the passes, or capture all entries into an array first: ```perl my @all; while (my @gr = getgrent) { push @all, [ @gr ] } endgrent; ``` The iterator is not reset when a subroutine returns. If library code you do not control calls `getgrent`, it moves your position. Guard with [`setgrent`](setgrent) when you need a clean start. ## Examples Walk every group and print the name and member count: ```perl while (my ($name, undef, $gid, $members) = getgrent) { my $n = length $members ? scalar(split ' ', $members) : 0; printf "%-16s gid=%d members=%d\n", $name, $gid, $n; } endgrent; ``` Collect all groups a given login belongs to: ```perl my $user = 'alice'; my @groups; while (my ($name, undef, undef, $members) = getgrent) { push @groups, $name if grep { $_ eq $user } split ' ', $members; } endgrent; ``` Scalar context — list every group name, one per line: ```perl while (defined(my $name = getgrent)) { print $name, "\n"; } endgrent; ``` Rewind and re-read, for example to build two indexes in one pass each: ```perl setgrent; my %by_name = map { $_->[0] => $_ } map { [ getgrent ] } 1 .. (); # collect… # …or just loop twice with an explicit setgrent before each pass. setgrent; while (my @gr = getgrent) { ... } endgrent; ``` Convert a numeric gid from [`stat`](stat) to a group name without a second lookup by caching the iterator output: ```perl my %name_of; while (my ($name, undef, $gid) = getgrent) { $name_of{$gid} = $name; } endgrent; my $gid = (stat $path)[5]; print "group: $name_of{$gid}\n"; ``` ## Edge cases - **End of iteration vs. a real entry**: in list context, an exhausted database returns the empty list — which assigns as zero elements, so `my @gr = getgrent; @gr or last;` is the idiomatic termination test. In scalar context, test with `defined` rather than truthiness, since a legitimate group name could in principle be the string `"0"`. - **No password field on modern Linux**: `$passwd` is almost always `"x"` (real hashes live in `/etc/gshadow`). Do not treat a non-`"x"` value as "password set" without consulting the shadow database. - **Empty `$members`**: groups with no explicit members (users listed only by primary gid) have `$members` as the empty string. `split ' ', ""` returns an empty list — the idiomatic way to get members as an array without a special case. - **Implicit primary-gid membership is not reported**: `$members` lists only the users explicitly named in the group's `/etc/group` record. A user whose primary gid matches this group but who is not also listed in the `members` field does **not** appear. Cross-check with [`getpwent`](getpwent) if you need both kinds of membership. - **Nested iteration clobbers position**: a second `getgrent` loop started before the first one finishes shares the same cursor. Use [`setgrent`](setgrent) between passes, or snapshot the database into memory up front. - **Taintedness**: the `$passwd` field is tainted under `-T`, same as for [`getpwent`](getpwent) — treat it as untrusted input even though the usual value is `"x"`. - **Process-wide, not thread-wide**: on systems without thread-safe variants the iteration state is per process, not per thread. Two threads walking `getgrent` at once will miss records. - **`endgrent` is optional but polite**: leaving the database open to program exit works, but if you are done iterating, call [`endgrent`](endgrent) so the C library can drop its buffers. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`getgrnam`](getgrnam) — single lookup by group name; use when you already know the name and want just one record - [`getgrgid`](getgrgid) — single lookup by numeric gid; the usual partner of [`stat`](stat) when you need a group name for a file - [`setgrent`](setgrent) — rewind the iterator to the start of the group database before another full-scan pass - [`endgrent`](endgrent) — close the database and release any resources the C library holds open - [`getpwent`](getpwent) — the parallel iterator over the passwd database; pair with `getgrent` when resolving full user-to-group relationships - [`scalar`](scalar) — force scalar context when you only need the group name and want to skip the other fields