Is there any command that can find the number of users that are not logged into the system ?

I am trying to write a shell script that counts the number of users who are logged in and number of users that are not logged in.

3 Answers 3


Listing out groups of users

You can get a list of all your local users with this command:

$ getent passwd | awk -F: '{print $1}'

NOTE: getent will return local users assuming you do not have sssd (or some similar service running which pulls LDAP users in too) and your /etc/nsswitch.conf is restricted to files, i.e. it's not including things like NIS or NIS+. For pure local user's only you can resort to awk -F: '{print $1}' /etc/passwd.

A list of who's currently logged in:

$ who

A list of user's that are currently not loggd in:

$ grep -Fxvf <(who | awk '{print $1}' | sort -u) \
    <(getent passwd | awk -F: '{print $1}')

This last one takes the list of users who are logged in and shows the list of all user's minus the logged in users, using grep -vf.

Getting counts

To get counts, simply take a wc -l on to the end of commands.

not logged in
$ grep -Fxvf <(who | awk '{print $1}' | sort -u) \
    <(getent passwd | awk -F: '{print $1}') | wc -l
logged in
$ who | awk '{print $1}' | sort -u | wc -l

grep flags

-F, --fixed-strings
        Interpret PATTERN as a list of fixed strings, separated by newlines, 
        any of which is to be matched.

-x, --line-regexp
        Select only those matches that exactly match the whole line.

-v, --invert-match
        Invert the sense of matching, to select non-matching lines.

-f FILE, --file=FILE
        Obtain patterns from FILE, one per line.  The empty file contains 
        zero patterns, and therefore matches nothing.

Using join instead of grep

You could also forgo using grep and use join instead, since this type of problem is more in join's wheelhouse. We'll need to use join -v 2 which means that we want to exclude matches and only show the uniques from our second argument, getent ....

join man page
        also print unpairable lines from file FILENUM, where FILENUM is 
        1 or 2, corresponding to FILE1 or FILE2

        like -a FILENUM, but suppress joined output lines

$ join -v 2 <(who | awk '{print $1}' | sort -u) \
    <(getent passwd | awk -F: '{print $1}' | sort) | wc -l

NOTE: The only caveat with using join is that both lists need to be sorted, so we have to add on a | sort to getent ....

  • getent will also list entries from LDAP, etc. Do those count as local?
    – muru
    Commented Dec 6, 2014 at 5:17
  • @muru - thanks for the feedback. I'm not sure that's true. I think that's the case only if sssd is running. In addition, by using getent, you need to make sure that /etc/nsswitch.conf is also only restricted to files, if you truly want local files. I'll add this as a note in my A, thanks again.
    – slm
    Commented Dec 6, 2014 at 15:13
  • @muru - yeah I used that one as an example, but I'm aware of there being others.
    – slm
    Commented Dec 6, 2014 at 15:17
  • 1
    @muru - I also added a pure /etc/passwd only option to show it. I hate to add that since it's generally discouraged to work against those files directly 8-)
    – slm
    Commented Dec 6, 2014 at 15:20
  • @muru - I find it a bit annoying that getent does not provide some switch for this. I searched but did not find one.
    – slm
    Commented Dec 6, 2014 at 15:21

This one-liner will work:

grep -Ev $(users | sed 's/ /|/g') /etc/passwd | awk -F: {'print $1'}

How it works:

The output of users | sed 's/ /|/g' will give you a | separated list of logged in users.

The -E option with grep will allow us to use more than one string (in OR condition) to match. The -v option will print out what does not match given strings/pattern. Combining -E and -v together will list all the lines that does not contain the pipe-separated strings from the output of users | sed 's/ /|/g'. At the end use awk to filter out only the usernames.


You may want to write a script that will store the number of users currently logged in a file and the total users in another file and do a comm over them.

For example:


w | awk 'NR > 2 {print $1}' | sort > logged.txt #sorted list of logged users
awk -F':' '{ print $1}' /etc/passwd | sort > allusers.txt #sorted list of all users
comm -23 allusers.txt logged.txt #find lines unique to allusers.txt

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .