I often want to get the login name associated with a user ID and because it’s proven to be a common use case, I decided to write a shell function to do this. While I primarily use GNU/Linux distributions, I try to write my scripts to be as portable as possible and to check that what I’m doing is POSIX-compatible.
Parse /etc/passwd
The first approach I tried was to parse /etc/passwd (using awk).
awk -v uid="$uid" -F: '$3 == uid {print $1}' /etc/passwd
However, the problem with this approach is that the logins may not be local, e.g., user authentication could be via NIS or LDAP.
Use the getent command
Using getent passwd is more portable than parsing /etc/passwd as this also queries non-local NIS or LDAP databases.
getent passwd "$uid" | cut -d: -f1
Unfortunately, the getent utility does not seem to be specified by POSIX.
Use the id command
id is the POSIX-standardised utility for getting data about a user’s identity.
BSD and GNU implementations accept a User ID as an operand:
This means it can be used to print the login name associated with a User ID:
id -nu "$uid"
However, providing User IDs as the operand is not specified in POSIX; it only describes the use of a login name as the operand.
Combining all of the above
I considered combining the above three approaches into something like the following:
get_username(){
uid="$1"
# First try using getent
getent passwd "$uid" | cut -d: -f1 ||
# Next try using the UID as an operand to id.
id -nu "$uid" ||
# As a last resort, parse `/etc/passwd`.
awk -v uid="$uid" -F: '$3 == uid {print $1}' /etc/passwd
}
However, this is clunky, inelegant and – more importantly – not robust; it exits with a non-zero status if the User ID is invalid or does not exist. Before I write a longer and clunkier shell script that analyses and stores the exit status of each command invocation, I thought I’d ask here:
Is there a more elegant and portable (POSIX-compatible) way of getting the login name associated with a user ID?