getpwnam#
Look up a user’s passwd record by login name.
getpwnam wraps the system C library’s getpwnam(3) call. Pass a
login name like "root" or "alice"; you get back the passwd entry
for that user, or an empty list / undef if no such user exists.
The return shape depends on context: list context gives every field
of the record; scalar context gives a single useful value — for
getpwnam specifically, the numeric UID.
Synopsis#
getpwnam NAME
What you get back#
List context returns a 10-element list mirroring struct passwd
augmented with the BSD extras:
my ($name, $passwd, $uid, $gid, $quota,
$comment, $gcos, $dir, $shell, $expire) = getpwnam($login);
$name— login name (same string you passed in)$passwd— encrypted password, or"x"/"*"on shadow-password systems. Tainted under-T.$uid— numeric user ID$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 $uid. For getpwnam — a lookup
by name — 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 — “user not found” is not a failure, it’s an empty return).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. Agetpwnamcall does not disturb an in-progressgetpwentloop on glibc, but portable code should not assume that.
Examples#
Basic name-to-UID lookup in scalar context:
my $uid = getpwnam("root"); # 0
Full record in list context, with a defensive check:
my @pw = getpwnam($user)
or die "$user: not in passwd database";
my ($name, undef, $uid, $gid, undef, undef, $gcos, $home, $shell) = @pw;
print "$name ($uid) -> $home, shell $shell\n";
Assignment pattern from upstream — unpacking directly with or die:
my ($login, $pass, $uid, $gid) = getpwnam($user)
or die "$user not in passwd file";
Comparing file ownership against a named user without hand-written
field indexing, via the User::pwent override:
use User::pwent;
use File::stat;
my $is_theirs = (stat($filename)->uid == getpwnam($whoever)->uid);
use User::pwent replaces getpwnam with a version returning a
blessed object with ->name, ->uid, ->gid, ->dir, ->shell
accessors — handy when you want one field and don’t want to count
commas. The two forms do not mix: inside one scope either use the
override or the built-in, not both.
Fallback chain for “who am I running as”:
my $login = getlogin() || getpwuid($<) || "unknown";
getpwuid is the by-UID counterpart; getlogin reads the
controlling-tty record and can lie on detached processes, so it’s
the first choice, not the only one.
Edge cases#
No such user returns the empty list in list context and
undefin scalar context. This is not an error —$!is not set. Distinguish “user missing” from “lookup failed” by checking$!only when you want to report an unexpected failure, not when deciding whether the user 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.Return value is a “single meaningless true value” in Boolean-ish scalar context when the entry exists but you wanted list context. The scalar-context documented return for
getpwnamis the UID, which forrootis0— a false value.if (getpwnam("root")) { ... }therefore fails for root. Usedefinedor list context:if (defined getpwnam("root")) { ... } # correct if (my @pw = getpwnam("root")) { ... } # also correct
Name is a string, not a UID.
getpwnam(0)stringifies0and looks up the literal user named"0", which almost never exists. Usegetpwuidfor numeric lookups.Large directories (LDAP / NIS / SSSD).
getpwnamgoes 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 looking up many users in a tight loop.Threads. Upstream notes that
getpwnam_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#
getpwuid— same record, looked up by numeric UID; pair withgetpwnamwhen you need to go UID → namegetpwent— iterate the whole passwd database; use when you need every user, not a specific onegetgrnam— 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 togetpwnam/getpwuidwhen it returns emptyUser::pwent— object wrapper with named accessors; reach for it when you want->uidinstead of counting list positions