How to List All Users in Linux
Operating systems based on the Linux kernel support multiple user accounts. Instead of "user accounts" they're often just called "users".
So let's see how to list all of these users / accounts. First, we'll explore the commands. And at the end of this blog we'll explain how the commands work.
List All Users on Linux
To list all the users on a Linux machine, we can run this command:
getent passwd | awk -F: '{ print $1 }'
We'll get a result like this:
This list is quite long. Do we really have so many user accounts on our system? Which person will log in as the user called "www-data" on this machine?
Well, no actual human being will log in as "www-data". But a program like the Apache web server will use that account to do some of its work.
Which means some of these users / accounts are meant to be used by programs. And others are meant for actual human beings. Linux-based operating systems call these:
- System accounts.
- User accounts.
If we're not interested in system accounts, we can filter our output this way.
List Regular (Non-System) User Accounts on Linux
To list just regular user accounts on a Linux system (accounts that are normally used by people), we can run this command:
getent passwd | awk -F: '($3>999){ print $1 }'
Now the output will be much shorter:
List Users that Belong to a Certain Group on Linux
On a system with many user accounts we might want to filter based on groups. Otherwise said, show only those users that belong to a certain group.
For example, maybe we want to see which users have administrative privileges. To do that, we can list users belonging to the "sudo" group:
getent group sudo | awk -F: '{ print $4 }'
And we'd get a list of usernames, separated by a ,
comma character:
If you're interested in users that belong to a different group, just replace sudo
, in the command above, with the group name you require.
Explaining the Commands
Now let's break down all of these commands, and see how they work.
First, when we listed all users on Linux we ran:
getent passwd | awk -F: '{ print $1 }'
Why is that? Well, let's explore the first part of the command.
Understanding the 'getent passwd' Command
Linux-based operating systems store a lot of the information they need in simple text files. So when you need to get information about users / accounts on a system, many people will recommend a command like:
cat /etc/passwd
Which will display the /etc/passwd
file, where Linux stores info about users / accounts.
And sure enough, it works… most of the time. But not always!
That's why we used getent passwd
instead. Which seems to show us the same thing as the cat /etc/passwd
command:
So, why getent passwd
? Because, in some cases, user / account information might not be stored entirely in the /etc/passwd
file. On some systems – for example those that use LDAP – some user information can be stored on a separate server.
Which means, you will get some user information from the /etc/passwd
file. But not all of it. Because some user accounts will be defined on a separate server, somewhere. So taking a look at the /etc/passwd
file might only give you partial data. While getent passwd
will show you the full picture:
- User data stored locally, in files like
/etc/passwd
. - But also user data stored on LDAP servers, or other remote places. (As long as the Linux machine is configured to use those as sources for additional user accounts).
Now, you might notice: The getent passwd
command shows us a lot of data:
Useful when you need all information about users / accounts. Such as: Number IDentifiers (IDs), what their home directories are, what shell program each account uses, and so on.
But when all you need is just a list of users / accounts, then the normal output of getent passwd
is quite messy.
That's why we needed the second part in our command: awk -F: '{ print $1 }'
. And how we ended up with:
getent passwd | awk -F: '{ print $1 }'
Let's explore that second part.
Filtering Output with awk to Show Just the Usernames
A command like
getent passwd
shows us this:
But,
getent passwd | awk -F: '{ print $1 }'
cleans up that output and shows us this:
This is called piping output to another command. Essentially, we:
- Take the (messy/overloaded) output from the
getent passwd
command. - And send it to a second command:
awk -F: '{ print $1 }'
. Which cleans up the output from the first command.
Think of awk
as a "programming language" that processes text. It helps you extract what you need, and / or transform the text / reformat it to something else.
Now let's understand how this part works:
awk -F: '{ print $1 }'
The command:
getent passwd
displays output like this:
Notice the format. We can see a user name like root, followed by the :
character, then some other data fields. Each field is separated by this :
character.
The first thing we do in:
awk -F: '{ print $1 }'
We tell awk
that what separates these fields is the :
character. That's the purpose of -F:
.
Then, we specify the "program" / instruction that awk
should run: print $1
. Which tells awk
: "Print the first field". If we'd want to print the second field, we'd write $2
. But we're interested in the first field, since that's where the username is located on each line, in our output.
This print $1
instruction is wrapped between { }
curly brackets, since that's the syntax that awk
expects. And, finally, we also wrap the curly brackets between ' '
single quotes. That's just to prevent our shell / command interpreter from misinterpreting what we wrote here. It's a way to tell our Bash shell:
"Look, about this thing wrapped between single quotes: It's for the awk
program, it's not for you. Please literally send this to the program, and don't try to interpret it / transform it in any way before doing that. Just send this text as I wrote it, don't interfere!"
So, wrapping all that up, we end up with this command:
getent passwd | awk -F: '{ print $1 }'
Which:
- Retrieves all user information available, with
getent passwd
. - Sends (
|
pipes) the output toawk
. - Tells
awk
that the field separator is:
. - And then instructs
awk
to print just the first field (the username, in this case).
And we get the output we needed:
Now let's explore the command that filters only non-system users / accounts. That works almost the same way, but it uses an additional awk
trick.
Filtering Output with awk to Show Only Non-System Accounts
To display only accounts meant for human beings, we used this command:
getent passwd | awk -F: '($3>999){ print $1 }'
Which showed us this output:
We can see we used the same tricks:
- We
|
pipedgetent passwd
output to theawk
program. - We told
awk
what the field separator is. - We instructed
awk
to print the first field.
But, we have an additional trick in there: ($3>999)
.
This essentially adds a condition to awk
, telling it:
"Only show me output where the third field ($3) contains a value LARGER than (>) 999. So, anything from 1000, and up."
Why? Because the getent passwd
command outputs lines like these:
alex:x:1000:1000:alex:/home/alex:/bin/bash
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
polkitd:x:998:998:User for polkitd:/:/usr/sbin/nologin
john:x:1001:1001:,,,:/home/john:/bin/bash
Note the third field on all lines. That's the user ID, a number uniquely identifying each user / account. And note that only "alex", "john", and "nobody" have an user ID larger than 999. One is 1000, one is 1001, and one is 65534. So only these three users will match the rule sent to awk
: "Third field has to be larger than 999."
That's why:
getent passwd | awk -F: '($3>999){ print $1 }'
will display this output:
Now you might ask: "But wait! Why does anything with an ID larger than 999 have any special meaning?" Well, that's just common practice on most Linux systems. By default, the system is configured so that:
- Any user account will be assigned an ID that is equal to 1000, or larger than 1000.
- Any system account will be assigned an ID that is smaller than 1000. Usually, anything with an ID between 100 and 999.
These settings for the IDs are defined in the /etc/login.defs
file. Some Linux distributions might make some adjustments to these defaults.
Hopefully, this demystified all the concepts we used in these commands. If not, ask away in the comments.
getent passwd | awk --field-separator=: '{ print $1 }'
But
--field-separator
only works with the gawk
utility (included by default on Ubuntu distributions). However, Debian uses mawk
, by default. And the mawk
utility does not understand the --field-separator
option. So--field-separator=:
was replaced with -F:
throughout this blog. To make sure it works on both Ubuntu, Debian, and most of the other popular Linux distributions.Reference for awk commands: