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.
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.
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.
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
| Command | Result | Typical use |
|---|---|---|
id -u | Effective user ID | Pass a numeric owner to a tool or script |
id -g | Effective group ID | Check the process's primary group |
id -G | All group IDs | Inspect 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.
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.
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.
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.
-g gives one effective group ID, while -G gives the complete group list.id's exit status before using its output, especially when the account name comes from input.id -Z requests only the security context. On a system without an SELinux-enabled kernel it reports the operation is unavailable; it does not enable SELinux.id.-u, -g, -G, and -n.-r.