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/$ageon 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-Tbecause 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 idiomgetpwuid($<)is what turns the real-UID special variable into a useful record.Under
-T(taint mode),$passwd,$gcos, and$shellcome back tainted. Seeperlsecfor how to launder them.Shares the same underlying iterator state as
getpwent,setpwent, andendpwent. Agetpwuidcall does not disturb an in-progressgetpwentloop 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
undefin 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.$passwdis 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 theAuthen::PAMmodule for authentication rather than comparing against this field.$quota,$comment,$expireportability. These fields are empty or meaningless on Linux. The upstream POD listsConfigvalues (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,$shellare tainted because users can modify them (viachsh,chfn, or direct/etc/passwdedits 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 forrootis the UID0(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 fordefinedanyway 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"to0(with a warning underuse warnings) and looks up UID0. Usegetpwnamfor name lookups.Negative / oversized UIDs. The system call accepts whatever
uid_taccepts 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).
getpwuidgoes 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. annotatingls -l-style output).Threads. Upstream notes that
getpwuid_ris used automatically where the platform provides it;getpwentiteration, 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 withgetpwuidwhen you need to go name → UIDgetpwent— iterate the whole passwd database; use when you need every user, not a specific onegetgrgid— group-database counterpart; needed to resolve the$gidfield from this record back to a group namegetlogin— cheap “who is on this tty” lookup; fall back togetpwuid($<)when it returns emptyUser::pwent— object wrapper with named accessors; reach for it when you want->nameinstead of counting list positions