User and group info

getpwuid#

Look up a user’s passwd record by numeric UID.

getpwuid wraps the system C library’s getpwuid(3) call. Pass a numeric user ID like 0 or $<; you get back the passwd entry for that user, or an empty list / undef if no such UID exists. The return shape depends on context: list context gives every field of the record; scalar context gives a single useful value — for getpwuid specifically, the login name.

Synopsis#

getpwuid UID

What you get back#

List context returns a 10-element list mirroring struct passwd augmented with the BSD extras — the same shape getpwnam returns:

my ($name,    $passwd, $uid,  $gid,   $quota,
    $comment, $gcos,   $dir,  $shell, $expire) = getpwuid($uid);
  • $name — login name

  • $passwd — encrypted password, or "x" / "*" on shadow-password systems. Tainted under -T.

  • $uid — numeric user ID (same number you passed in)

  • $gid — numeric primary group ID

  • $quota — disk quota, or $change / $age on some systems. Empty string when unsupported.

  • $comment — administrative comment, sometimes $class. Empty string when unsupported.

  • $gcos — GECOS field (usually the real name plus other user info). Tainted under -T because users can edit it.

  • $dir — home directory

  • $shell — login shell. Tainted under -T.

  • $expire — account / password expiration, when supported.

Scalar context returns just $name (the login name). For getpwuid — a lookup by UID — scalar context gives you “the other thing,” matching the rule upstream documents for all getpw* / getgr* / gethost* / getnet* / getproto* / getserv* functions.

On lookup failure both contexts return the empty list / undef. Always check the return before unpacking.

Global state it touches#

  • Sets $! on system-call failure (rare — “UID not found” is not a failure, it’s an empty return).

  • Reads $< and $> implicitly only when you pass them in, but the common idiom getpwuid($<) is what turns the real-UID special variable into a useful record.

  • Under -T (taint mode), $passwd, $gcos, and $shell come back tainted. See perlsec for how to launder them.

  • Shares the same underlying iterator state as getpwent, setpwent, and endpwent. A getpwuid call does not disturb an in-progress getpwent loop on glibc, but portable code should not assume that.

Examples#

Basic UID-to-name lookup in scalar context:

my $name = getpwuid(0);             # "root"

“Who am I running as” — the canonical getpwuid idiom, resolving the real UID to a login name:

my $me = getpwuid($<);              # e.g. "alice"

Pair with getlogin for a reliable fallback chain that survives detached processes and su sessions:

my $login = getlogin() || getpwuid($<) || "unknown";

getlogin reads the controlling-tty record and can lie (or return empty) when there is no tty; getpwuid($<) answers from the kernel’s recorded UID and always works.

Full record in list context, with a defensive check:

my @pw = getpwuid($uid)
    or die "uid $uid: not in passwd database";
my ($name, undef, undef, $gid, undef, undef, $gcos, $home, $shell) = @pw;
print "$name ($uid) -> $home, shell $shell\n";

Go UID → group name via the $gid field:

my $gid      = (getpwuid($<))[3];
my $groupnam = getgrgid($gid);

Object-style access via the User::pwent override, useful when you want named accessors instead of counting list positions:

use User::pwent;
my $pw = getpwuid($<);
printf "%s lives in %s, runs %s\n", $pw->name, $pw->dir, $pw->shell;

use User::pwent replaces getpwuid with a version returning a blessed object with ->name, ->uid, ->gid, ->dir, ->shell accessors. The two forms do not mix: inside one scope either use the override or the built-in, not both.

Edge cases#

  • No such UID returns the empty list in list context and undef in scalar context. This is not an error — $! is not set. Distinguish “UID missing” from “lookup failed” by checking $! only when you want to report an unexpected failure, not when deciding whether the UID exists.

  • $passwd is rarely useful. On modern Linux and BSD systems the real hash lives in /etc/shadow, readable only by root. You get "x" or "*" here. Use PAM or the Authen::PAM module for authentication rather than comparing against this field.

  • $quota, $comment, $expire portability. These fields are empty or meaningless on Linux. The upstream POD lists Config values (d_pwquota, d_pwage, d_pwchange, d_pwcomment, d_pwexpire) you can check if you need to know at runtime whether the platform populates them.

  • Tainted fields under -T. $passwd, $gcos, $shell are tainted because users can modify them (via chsh, chfn, or direct /etc/passwd edits in privileged contexts). Pass them through a regex capture to launder before using in a system call.

  • Scalar-return on UID 0 is never false. Unlike getpwnam, whose scalar return for root is the UID 0 (a false value), getpwuid’s scalar return is the name "root" — always a true string for existing users. if (getpwuid($uid)) { ... } therefore works as you would expect, but reach for defined anyway if you care about the distinction between “missing” and “empty name”:

    if (defined getpwuid($uid))       { ... }   # unambiguous
    if (my @pw = getpwuid($uid))      { ... }   # also correct
    
  • UID is a number, not a name. getpwuid("root") stringifies "root" to 0 (with a warning under use warnings) and looks up UID 0. Use getpwnam for name lookups.

  • Negative / oversized UIDs. The system call accepts whatever uid_t accepts on the platform (typically 32-bit unsigned). Perl converts negative values via two’s-complement on the way in; the result is platform-specific and almost never what you want.

  • Large directories (LDAP / NIS / SSSD). getpwuid goes through NSS, so the cost scales with however the local resolver answers. A miss against a misconfigured LDAP server can block for seconds. Cache results in a hash if you are resolving many UIDs in a tight loop (e.g. annotating ls -l-style output).

  • Threads. Upstream notes that getpwuid_r is used automatically where the platform provides it; getpwent iteration, by contrast, remains per-process. Not a concern under pperl (no ithreads), but worth knowing if you share code with perl5.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • getpwnam — same record, looked up by login name; pair with getpwuid when you need to go name → UID

  • getpwent — iterate the whole passwd database; use when you need every user, not a specific one

  • endpwent — close the passwd iterator after getpwent

  • getgrgid — group-database counterpart; needed to resolve the $gid field from this record back to a group name

  • getlogin — cheap “who is on this tty” lookup; fall back to getpwuid($<) when it returns empty

  • User::pwent — object wrapper with named accessors; reach for it when you want ->name instead of counting list positions