--- name: endgrent signature: 'endgrent' since: 5.0 status: documented categories: ["User and group info"] --- ```{index} single: endgrent; Perl built-in ``` *[User and group info](../perlfunc-by-category)* # endgrent Close the group database after iterating it. `endgrent` is the cleanup half of the group-database iteration trio [`setgrent`](setgrent) / [`getgrent`](getgrent) / `endgrent`. It tells the C library that you are done walking `/etc/group` (or the NSS source behind it), releasing any file descriptors or cached state the library opened on your behalf. After `endgrent`, the next [`getgrent`](getgrent) call starts a fresh iteration from the top. ## Synopsis ```perl endgrent; endgrent(); ``` No arguments, no meaningful return value. ## What you get back The return value is unspecified and must not be relied on. `endgrent` is called for its side effect — closing the group database — not for a result. Treat it as a void call. ```perl endgrent; # correct my $ok = endgrent; # wrong: $ok is not a success flag ``` If your platform does not implement `endgrent`, the call croaks with `The endgrent function is unimplemented` at runtime. This is effectively a compile-once check — if the function works on your system at all, it will continue to. ## Global state it touches `endgrent` operates purely on the libc-internal group-iteration state that [`setgrent`](setgrent) and [`getgrent`](getgrent) share. It reads and writes no Perl special variables. It does not alter [`$!`](../perlvar): a failure path that sets `errno` in the underlying C call is not surfaced to Perl. The iteration state is **per-process**, not per-thread. In a threaded program, one thread's `endgrent` closes the iteration for every thread — see *Edge cases*. ## Examples The canonical iterate-and-close pattern. Always pair a [`setgrent`](setgrent) / [`getgrent`](getgrent) loop with `endgrent` so long-running programs do not leak the file descriptor the C library keeps open: ```perl setgrent; while (my @g = getgrent) { my ($name, $passwd, $gid, $members) = @g; print "$name ($gid): $members\n"; } endgrent; ``` Dropping into `endgrent` mid-iteration is legal — it simply abandons whatever cursor position the library was holding: ```perl setgrent; while (my @g = getgrent) { last if $g[0] eq 'wheel'; # found what we wanted } endgrent; # release the handle anyway ``` Restarting iteration. `endgrent` followed by [`setgrent`](setgrent) is the portable way to rewind: ```perl setgrent; my @first_pass = collect_groups(); endgrent; setgrent; my @second_pass = collect_groups(); # starts over from the top endgrent; ``` Defensive cleanup in a `END` block for programs that might die mid-walk: ```perl setgrent; END { endgrent } while (my @g = getgrent) { ... } # any die still triggers END ``` ## Edge cases - **Calling `endgrent` without a prior [`setgrent`](setgrent) or [`getgrent`](getgrent)** is harmless. The C library silently does nothing if no iteration is in progress. - **Calling it twice in a row** is also harmless — the second call is a no-op. - **Parser ambiguity.** `endgrent` takes no argument and has the precedence of a named unary operator. A bareword expression immediately to its right will be parsed as an argument and rejected: ```perl endgrent or die; # WRONG: parses as endgrent(or die) endgrent() or die; # right: empty parens disambiguate ``` In practice there is nothing to check the return value against, so this trap rarely bites — but the same rule applies to any chained expression. - **Threads share the iteration.** `endgrent` from one thread ends iteration for all threads of the same process, because the underlying state is process-global. Do not interleave [`getgrent`](getgrent) calls across threads expecting each to see every record. - **NSS and caching.** On systems where the group database is served through NSS (nss_ldap, nss_sss, etc.), `endgrent` releases per-module caches that the NSS backend may hold. Long-lived daemons that walk the group database periodically should call `endgrent` after each walk to avoid accumulating backend state. - **No effect on name-lookup calls.** [`getgrnam`](getgrnam) and [`getgrgid`](getgrgid) are independent of the iteration cursor. `endgrent` does not invalidate their results or cached data, and you do not need to call `endgrent` before or after them. - **Unimplemented on some platforms.** Perl croaks `The endgrent function is unimplemented` if the host libc has no `endgrent(3)`. All modern Linux, BSD, and macOS systems provide it. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`setgrent`](setgrent) — open or rewind the group database before walking it; always the prologue to an iteration that ends with `endgrent` - [`getgrent`](getgrent) — pull the next record from the iteration `endgrent` closes - [`getgrnam`](getgrnam) — look up one group by name, independent of the iteration cursor; no `endgrent` needed - [`getgrgid`](getgrgid) — same as [`getgrnam`](getgrnam) but keyed on numeric gid - [`endpwent`](endpwent) — the parallel cleanup call for the passwd database; the two iterations are independent and both need closing if you opened both