Read Linux User and Group IDs Reliably with id

Scripts that trust whoami eventually break, which is why id exists: it reads the real user and group IDs behind any account. This guide covers the current process, a named account, numeric versus name output, and group membership without surprises from the default format. The examples use GNU coreutils 9.4, the version installed on the machine used here.

Before you start

You need a shell and the GNU id command, normally installed with the coreutils package. No elevated privileges are needed for anything below. Allow about five minutes to run the examples and compare them with your own account.

Checkpoint: Confirm the version before relying on any behaviour in a script.

$ id --version
id (GNU coreutils) 9.4

The version number may differ on another distribution. The option meanings used here belong to the GNU command documented by the local manpage.

1. See the current process identity

Run id with no options. It reports the current process: user ID, primary group ID, and supplementary groups, with names in parentheses after the matching numbers.

$ id
uid=1000(alice) gid=1000(users) groups=1000(users),27(sudo),987(docker)

Your numbers and names will differ. The part before the first group is the user identity. gid is the effective primary group. The groups list includes that group plus any supplementary groups available to the process.

This is a diagnostic command, not a membership editor. It does not add the account to a group or change the process identity.

2. Ask for one identity at a time

Use the short options when another command needs a single value. Each of these writes only the requested value followed by a newline:

$ id -u
1000
$ id -g
1000
$ id -G
1000 27 987 1001
CommandResultTypical use
id -uEffective user IDPass a numeric owner to a tool or script
id -gEffective group IDCheck the process's primary group
id -GAll group IDsInspect supplementary group membership

Checkpoint: If a script needs one number, use id -u or id -g, not the human-readable default line. That skips having to parse labels and parentheses.

3. Choose names, real IDs, or effective IDs

Add -n to -u, -g, or -G when names are more useful than numbers.

$ id -n -u
alice
$ id -n -g
users
$ id -n -G
users sudo docker alice

The -r option asks for the real ID instead of the effective ID. It matters most in a program that has changed identity, such as a set-user-ID program. Combine it with the selector:

$ id -r -u
1000
$ id -n -r -u
alice

Do not read -r as "the account that originally logged in". It asks the operating system for the real user or group ID tied to the process. Without -u, -g, or -G, the default report is used instead.

4. Inspect a named account

Pass a user name to see that account's identity rather than the current process. This reads account and group information; it does not switch users and does not run a command as that account.

$ id root
uid=0(root) gid=0(root) groups=0(root),994(kvm),986(ollama)

Options can be combined with a name when you need a machine-friendly value:

$ id -u root
0
$ id -n -g root
root

If the account does not exist, id prints an error and exits with status 1.

$ id definitely-no-such-user
$ echo $?
1

In a script, test the exit status rather than assuming an empty or partial result means "not found". Quote a user name that comes from a variable before passing it to the shell, and treat account names as data.

5. Make group output safe for a pipeline

id -G separates group IDs with spaces. For predictable processing, id -z -G separates them with NUL characters instead, which is useful once the next tool accepts NUL-delimited input and you do not want whitespace mistaken for a separator.

$ id -z -G | od -An -t x1
 31 30 30 30 00 32 37 00 39 38 37 00

The 00 bytes are the delimiters. The -z form is not permitted with the default, descriptive output, so pair it with a selector such as -G. Do not pipe this form into a command that expects ordinary text lines unless you deliberately want NUL bytes.

Common traps and boundaries

Done means