5

I want to know how many local users there are. How can this be done from a command line?

Note: I am not looking for a list of the users, I can do that easily enough.

12
  • 1
    if you can make a list of the users, then wc -l or wc -w will count them, depending on whether they are one per line or on the same line. I thought I could do it with ls -lat /Users | awk '{print $3}' | sort -u | grep -v root | wc -l but that gets one too many because it also counts the first line of ls which has nothing in column 3
    – WGroleau
    Commented Apr 12, 2023 at 6:23
  • @WGroleau just use ls without any options, none of them are required here. Neither is sorting the list, actually.
    – nohillside
    Commented Apr 12, 2023 at 6:37
  • 3
    @zeeple How do you get a list of the local users - as the answers show different numbers depending on how you get that list
    – mmmmmm
    Commented Apr 12, 2023 at 10:44
  • 1
    @WGroleau well, ok, if you assume /Users includes entries not related to user homes, then indeed you need ls -l /Users. But then you also need to grep -v for the guest account (which at least on my Mac here belongs to uid 201). Kind of amazing how challenging such a simple question can be :-)
    – nohillside
    Commented Apr 12, 2023 at 14:10
  • 1
    So taking this all into account, starting of with ls -l /Users might not be the best approach on this. Wonder how the AppleScript solution actually does the counting, seems to be the easiest way right now (querying dscl might work as well but might need work than just having it list the users).
    – nohillside
    Commented Apr 12, 2023 at 14:46

4 Answers 4

1

You can use wc -l with ls -A.

First, open Terminal and run cd /Users.

Then, since running ls -A gives you the list of all users (one per line) and wc -l the number of lines in your Terminal window, running ls -A | wc -l (getting the number of lines for a given command) will give you the number of lines given by ls -A and therefore giving you the number of users on the mac. But, there might also be one entry (for some people who did touched the /Users folder) /Users/Shared which is obviously not a user. You can just take the number got before (with ls -A | wc -l) and substract 1 to that, it will give you the exact number of users. See also @nohillside's comment on how to do that automatically (without having to do -1). Also, there might be other files, but just check if there's some "users" that aren't really ones and substract the number to the total.

Note that you can directly get info from the /Users/ folder by using ls /Users | wc -l. (From @zeeple's comment)

8
  • This is perfect. I changed it slightly to 'ls /Users | wc -l' but this is exactly what I was looking for. Thank you!
    – zeeple
    Commented Apr 11, 2023 at 17:59
  • 2
    I have /Users/Shared here which isn't an actual account so I assume that the result is off by one user.
    – nohillside
    Commented Apr 11, 2023 at 19:22
  • 3
    echo $(( $(ls /Users | wc -l) - 1 )). Not as short as before but the result is a bit closer to reality.
    – nohillside
    Commented Apr 11, 2023 at 19:38
  • 1
    This assumes one has never tapered with /Users. Mine has four items that are not user homes and not Shared. Three I put there and one of them (I don't know why is "Music Library.musiclibrary" put there by the Music.app
    – WGroleau
    Commented Apr 12, 2023 at 6:16
  • 2
    When I do ls -A I also see a file .localized. I don't think usernames can begin with ., so there's no reason to use the -A option.
    – Barmar
    Commented Apr 12, 2023 at 15:51
9

Although macOS seemingly does not provide a command-line method for listing real interactive users, we can take a shortcut and get CoreServices to do the hard work for us using AppleScript:

$ osascript -e 'tell application "System Events" to count user'
1

This should correspond to the number of accounts you see in System Preferences.

Unfortunately, this method may trigger a GUI alert for approving automation of System Events by your terminal or shell program.

4
  • This should be the right answer in my opinion. However, 1. I don't think the comment nor the \ns requiring $ are useful; you can use multiple -e for each 'line'. 2. You can use to to remove the need to end tell: tell application "System Events" to count user.
    – grg
    Commented Apr 12, 2023 at 9:42
  • This should be the answer since users do not need a home folder, could share a home folder and have it in a location other than /Users in the filesystem.
    – bmike
    Commented Apr 12, 2023 at 15:40
  • @grg I did initially try to use to but it triggers a syntax error due to specifying -- ACCOUNTS and so I didn't bother too much with trying to slim that down more.
    – kouwei32
    Commented Apr 12, 2023 at 17:31
  • 2
    @kouwei32 That's why I said I don't think the comment is useful, just remove it.
    – grg
    Commented Apr 12, 2023 at 17:41
6

Quick Method…

To get a list of the users via command line, use awk in conjunction with dscl

awk '! /^_/ {print} END{print NR}' <<< $(dscl . -list users)

When you use the command dscl . -list users, you’ll get every user including users for services and daemons.

  • To exclude this, we do a negative pattern match using awk. The ! /^_/ will match everything that doesn’t begin with an underscore.

  • The {print NR} will output the number of records that is generated. This will be the number of users.

Dedicated Function/Script

I created a small function/script that will use two built in utilities:

  • dscl . -list /Users to get a list the users
  • dsmemberutil checkmembership -U <username> -G <group> to verify the user is a member of a particular group. This will help in weeding out both user and system daemons and limit it only to actual users.

The script works by taking the list of users generated by dscl and querying each one against a known group; in this case Staff. It will print the users of that group and a count.

You can create a group specifically for student users and filter on that for more accuracy..

The group name can be modified as needed. The script below is setup as a function.. Source the file (in .bash_profile, zprofile or similar) then call the function name. The alternate is to extract the code (between the braces - { } - and run it as a script.

Below is an example of how it works.

% . ./users.sh          <——— sourcing the file
% listUsers             <——- calling the function

allan
testdude

Number of Users on this Mac: 2

Copy and paste this to a script or directly into .bash_profile or .zprofile. Source the file or close and re-open Termina/iTerm and call the function. If pasting as a standalone script, copy what is between the braces ({ }) only.

listUsers () 
{ 

local userGRP="Staff"
local count=0
declare -a users_arr=($(dscl . -list /Users))

for uname in  ${users_arr[@]}
do
  result=$(dsmemberutil checkmembership -U $uname -G $userGRP)
  if [[ $result =~ "is a member" ]]
  then
    printf "%s\n $uname"
    ((count++))
  fi
done

printf "\n\nNumber of Users on this Mac: %s\n\n"  $count

} 

Both of these solutions will work in both Bash (3.x) and Zsh. Meaning, they will work on older versions of macOS that have the default Bash shell as well as new versions with Zsh

2
  • I see users called com.apple.calendarserver, daemon, nobody and root with this, and NR also counts the non-matching lines (so it is 131 in my case). Don't think you can avoid having to actually count the relevant lines (or filter the list before running awk but then you can also just use wc -l).
    – nohillside
    Commented Apr 11, 2023 at 19:26
  • 1
    This should be the selected answer cause I gave this thread to my boss who was counting users by hand on all the work macs and he said this script saved him so much time. Thanx! Commented May 13, 2023 at 18:08
1

Answers and comments have provided several methods that will usually work but are not guaranteed.  Here's yet another unreliable method:

sudo last | awk '{print $1}' | sort -u | egrep -v "(reboot|shutdown|wtmp)"

will list every user that has logged in recently.  It may include root. So

sudo last | awk '{print $1}' | sort -u | egrep -v "(reboot|shutdown|wtmp)" | wc -l

will count them.  But subtract one (1) because last also includes a blank line.

I don't know exactly what "recently" means, but the last three lines from last on my system just now are:

WGroleau@MBP ~ % date; last | tail -3
reboot    ~                         Mon Oct 24 22:47 

wtmp begins Mon Oct 24 22:47 
0

You must log in to answer this question.

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