User and group info

endgrent#

Close the group database after iterating it.

endgrent is the cleanup half of the group-database iteration trio setgrent / 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 call starts a fresh iteration from the top.

Synopsis#

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.

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 and getgrent share. It reads and writes no Perl special variables. It does not alter $!: 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 / getgrent loop with endgrent so long-running programs do not leak the file descriptor the C library keeps open:

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:

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 is the portable way to rewind:

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:

setgrent;
END { endgrent }
while (my @g = getgrent) { ... }    # any die still triggers END

Edge cases#

  • Calling endgrent without a prior setgrent or 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:

    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 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 and 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 — open or rewind the group database before walking it; always the prologue to an iteration that ends with endgrent

  • getgrent — pull the next record from the iteration endgrent closes

  • getgrnam — look up one group by name, independent of the iteration cursor; no endgrent needed

  • getgrgid — same as getgrnam but keyed on numeric gid

  • endpwent — the parallel cleanup call for the passwd database; the two iterations are independent and both need closing if you opened both