How can I list all human users that I've created? I've tried cat /etc/passwd
and it just lists a lot of stuff.
8 Answers
Human users have UIDs starting at 1000, so you can use that fact to filter out the non-humans:
cut -d: -f1,3 /etc/passwd | egrep ':[0-9]{4}$' | cut -d: -f1
This cuts the first (username) and third (UID) colon-delimited fields from /etc/passwd
, then filters for the resulting lines which end with a colon and four digits, then cuts the first (username) field from that, leaving you with a list of users with UIDs between 1000 and 9999.
If you have more than nine thousand users on your system, this will fail - but it's necessary to restrict the result to 4-digit UIDs in order not to catch nobody
(UID 65534).
I personally like to use just:
ls /home
Admittedly this is not a list of users but instead a list of their home directories. Currently existing human users on the system will have home directories in /home
, but you may see the home directories of past users who were removed, as well.
This works for my purposes and may work for yours as well. For example, if you are looking to delete a user account that turns out no longer to exist (nonexistent-user
) and run the command
sudo deluser nonexistent-user
it will just tell you that that this user does not exist.
-
2+1 This way is simple, it's what most experienced users would actually do, and I think it's no less robust than methods that check a range of UIDs. It seems less likely a human user would have a home directory outside
/home
(that isn't symlinked to/home
) than that a human user would have a UID of under 1000 (after all, this is the most common method of keeping a display manager from listing a user on the login screen, which may sometimes be done for a human user). The one, relatively minor disadvantage here is thatlost+found
will be listed on systems with separate/home
partitions. May 1, 2015 at 0:01 -
Small problem, though: what happens if user was created with
useradd --no-create-home username
? May 1, 2015 at 2:03 -
1@Serg I think it comes down to the inherent ambiguity in the problem description. Does an account with no home directory really represent a human user? In practice, such accounts are usually--though admittedly not always--used for highly specialized tasks (typically by people with their own separate accounts) or for users intended to access the system only through specific, restricted services. Of course there's another use case for
useradd --no-create-home
--the home directory might already exist or might be created shortly thereafter--but thels /home
method works fine for those cases. May 1, 2015 at 2:46 -
What happens if someone creates a folder not associated with a user or with a human user? For example a folder for shared files Dec 12, 2021 at 17:12
This does pretty much what the accepted answer does, just in one command instead of three:
awk -F: '$3 >= 1000 && $1 != "nobody" {print $1}' /etc/passwd
And thanks to Karel in the comments, the nobody
user is also filtered out.
-
@karel Yeah, maybe. Instead of filtering by UID, I'm filtering out that username explicitly. There may be a reason for having a legitimate user with a UID that high... Who knows ;)– Oli ♦Aug 7, 2013 at 11:37
While it might seem like a clear-cut idea, actually there is ambiguity in the meaning of human user. Is a user account deliberately hidden from the login screen because it's used only for specialized purposes (but by humans) a human user? How about the ubuntu
user (UID 999) on the live CD? And guest accounts in Ubuntu are created on-the-fly and destroyed after logout; are they human users? More examples could be devised.
Therefore, it's fitting that multiple, non-equivalent answers have been given. Saige Hamblin's solution of running ls /home
is what people actually do, and unless you're writing a script, you should probably just use that.
Making ls /home
More Robust
But perhaps you have users that have been removed, but whose home directories still exist in /home
, and you must avoid listing them. Or maybe for some other reason you must ensure only the entries in /home
that correspond to real accounts are listed.
In that case, I suggest passing the names of everything in /home
to getent
(to retrieve the passwd
entries of users with those names), then isolate and display just the username field (with grep
, sed
, or awk
, as per your preference). Any one of these will do:
getent passwd $(ls /home) | grep -o '^[^:]*'
getent passwd $(ls /home) | sed 's/:.*//'
getent passwd $(ls /home) | awk -F: '{print $1}'
This should work well, as you shouldn't have user accounts with whitespace or control characters in their names; cannot, without reconfiguring Ubuntu to allow it; and if you do, you have bigger problems. Thus the usual problems with parsing ls
are inapplicable. But even though it's really okay here, if you consider command substitutions with ls
aesthetically displeasing or just a bad habit, you may prefer:
getent passwd $(basename -a /home/*) | grep -o '^[^:]*'
getent passwd $(basename -a /home/*) | sed 's/:.*//'
getent passwd $(basename -a /home/*) | awk -F: '{print $1}'
These don't accommodate whitespace or control characters either. I provide them only because $(ls /home)
looks wrong even when it is right, and thus rubs many users the wrong way. In most situations, there are real, good reasons to avoid parsing ls
, and in those situations parsing basename -a
is usually only very slightly less bad. In this situation, however, due to the limitation on what characters may practically occur in usernames, they are both fine.
Explanation, Benefits, and Drawbacks
I use getent
mainly because it accepts usernames as arguments to restrict its output, but also because it is slightly more universal than examining /etc/passwd
directly, in case authentication facilities and the password database are provided by network services.
This method has the additional benefit over ls /home
that, on systems with a separate /home
partition, lost+found
usually appears in the output of ls /home
.
- With the more robust method presented above,
lost+found
will only appear if there happens to be a user (human or not) calledlost+found
, which is unlikely. - But if you're entering commands interactively rather than writing a script,
ls /home
is fine--you know you don't have a human user calledlost+found
.
Infrequently, this method (in any of the above variations) will produce unsatisfactory output:
- If a user's home directory exists outside
/home
, or not at all, this suggests but does not imply the account shouldn't be considered to represent a human user. This method only lists users when there is a directory of the same name in/home
. - If you have created additional directories in
/home
that aren't actually anybody's home directory, and they happen to have the same name as an existing non-human user--or consist of words separated by whitespace, one or more of which has the same name as an existing non-human user--then some non-human users may be included in the output.
(This method can be implemented with a loop and separategetent
invocations, so word splitting doesn't produce spurious output. But the complexity is not warranted; fundamentally, if you use/home
as something other than a place for users' home directories, this method will not produce reliable output.)
Making UID Checking Simpler
If you decide to go with a method that checks user IDs to ensure they are in the likely range for accounts representing human beings, as in the accepted answer or Oli's answer, then I suggest this for brevity:
getent passwd | grep -oP '^[^:]+(?=:x:\d{4}:)'
This uses a Perl regular expression (-P
) to show:
- text at the beginning of a line (
^
) containing no:
s ([^:]+
) — this is the first field, as:
is the field separator inpasswd
- that precedes but doesn't include (
(?=
)
) the password fieldx
— it should always bex
, since in Ubuntu password hashes are stored in theshadow
database, not the world-readablepasswd
database - and a UID field consisting of exactly 4 digits (
:\d{4}:
).
This is thus a significantly shorter and somewhat simpler variant of the technique in the accepted answer. (The technique described there works fine too, and it does have the benefit of being portable to non – GNU/Linux systems whose grep
doesn't support -P
.)
Reconsidering the "Human" UID Range
If you want to accommodate very high UIDs and check for nobody
explicitly, you can use the method in Oli's answer. You may wish to consider, however, if users with very high UIDs should really be assumed human, or if they are more likely to be some other special-purpose non-human user (like nobody
). In practice such users--besides nobody
--are uncommon, so really this is a judgment call on your part.
A possible compromise is to list users in the range of UIDs that are actually being assigned to newly created, non-"system" users. You can check for this in adduser.conf
:
$ grep -E '^(FIRST|LAST)_UID' /etc/adduser.conf
FIRST_UID=1000
LAST_UID=29999
Here are two ways to list users whose UIDs range from 1000 to 29999:
getent passwd | grep -oP '^[^:]+(?=:x:[12]?\d{4}:)'
getent passwd | awk -F: '999<$3 && $3<30000 {print $1}'
-
If you wanted to be stylistically pleasing,
basename
is ugly. It is no better thanls
. The principle reason we don't parse ls is that it is a job that can be done by other tools much more safely and cleanly, not style. In this case, the shell:cd /home; getent passwd *
.– muruMay 1, 2015 at 5:20 -
I agree with you on /home being unreliable (it's useless for me, see my answer). I'm just saying that if you are going to preach about style, expect nitpicking.– muruMay 1, 2015 at 5:38
-
@muru I see how my original phrasing could mislead people to think avoiding parsing
ls
is usually about style. The 2nd bullet point about "unsatisfactory output" covered the issue, but it appears in a later section. I've reworded to clarify why parsingls
is appropriate in this situation. Althoughcd /home; getent passwd *
take a form often indicative of a sounder approach, I've avoided it so as not to lead readers to believe the contents of/home
directories, with weird added entries not corresponding to real users, could still somehow be relied on as a guide to what users exist. May 1, 2015 at 5:53
TL;DR: only human users have SystemAccount=false
One other way is to list output of while ignoring root ls /var/lib/AccountsService/users/ | grep -v root
. Now, there is a quirk - gdm, a greeter/login screen ( or more formally desktop manager ) is also listed as a user. So just from listing we cant tell if gdm is human or not.
A more efficient and correct approach is to go through the files in that folder and find out which users are listed as having SystemAccount=false
. The one-liner bellow achieves that
grep SystemAccount=false /var/lib/AccountsService/users/* | awk -F '/' '{gsub(":","/");print $6}'
-
1Although sometimes handy, this fails in some relatively common scenarios. For example, on my Ubuntu 15.04 minimal system (installed from
mini.iso
and with no display managers or X11 installed), I have one human user account--yet/var/lib/AccountsService/users
is an empty directory. I expect this will similarly not work on an out-of-the-box Ubuntu Server installation. Furthermore, when this does work, it does so under a somewhat restrictive notion of what makes a user account "human": making a user withuseradd
, even without--system
, doesn't create a file inAccountsService/users
. May 1, 2015 at 1:51
Joining the party, I oversee a network systems using LDAP, having home directories outside /home
and UIDs (due to a scripting glitch) in the millions. None of the current answers, therefore, work. The test that works for me is checking whether the user has a valid login shell. A valid shell is one which is listed in /etc/shells
. The simplest form:
getent passwd | grep -wFf /etc/shells
The file may contain comments (or empty lines), so one might have to filter them out:
getent passwd | grep -wFf <(grep '^/' /etc/shells)
-
+1 This may be the most robust approach suggested so far. Although it has the disadvantage of showing
root
(which probably shouldn't be considered a human user, since humans usually become root temporarily and for specific purposes, rather than using it for their regular work), it seems like it's the least likely to fail in any major way. The methods in other answers (including mine) may fail, depending on the method, if home directories aren't in/home
, other garbage is in/home
, UIDs are weird, or the system doesn't use a DM. This answer works pretty well in all those scenarios. May 1, 2015 at 6:05
On buntu systems, regular users (human users, that is) have UIDs beginning with 1000 which are assigned sequentially to them when their accounts are first created. What all this boils down to is that the first account created on a buntu system has a UID of 1000. The next one created has a UID of 1001. And so on and so forth.
So, the simplest way to list all human user accounts present on the system, in my opinion, is to check whether the third column in the /etc/passwd
file which contains the user's UID is greater than or equal to 1000 and less than, let's say, 2000 (it's very unlikely for a typical desktop PC to have more than one thousand user accounts, don't you think so?):
$ awk -F$':' '{ if ($3 >= 1000 && $3 < 2000) print $1; }' /etc/passwd
-
Thanks for explaining Oli's answer with details. You also need to filter out
nobody
. =) Mar 21, 2017 at 6:56 -
1You don't have to because nobody has a UID of 65534 and thus is automatically filtered out as all other nonhuman user accounts.– mishaMar 21, 2017 at 6:58
grep -E "x:[1-9]([0-9]){3}:" /etc/passwd
It browses the content of /etc/passwd looking for entries of human users.
To do that grep looks for lines that have user id numbers bigger than 1000.
Examples of matching regex:
x:1001:
x:1203: