macOS is a Unix system. However, it doesn’t conform to many conventions of common Unix systems. This text discusses these differences, not in the implementation level, but in the perspective of technical users, e.g. system administrators and application programmers.
macOS manages users and groups by directory services instead of
/etc/group. Consider a local
network, for example, the one in your office. There are many computers
in the network, and each has its own files,accounts, etc. A directory
service organizes these distributed resources into one single index, and
makes them look like a directory hierarchy.
/Hosts/PC1 represents a host in the
/Users/Smith represents a user in the
macOS uses the
dscl command to interact with directory
To list all users on the system, we could run the following.
dscl . -list /Users
The first argument sets which data source we want to retrieve from. A dot means the local data source.
# List groups dscl . -list /Groups
-list option lets
dscl print items of a
resource. Items of
/Users are all users. Items of
/Groups are all groups.
If we want to check the information about the resource, we should use
-read. For example, we could check the information of the
# Retrieve the information of Smith dscl . -read /Users/Smith
-read prints keys and values of the specified resource.
We could also specify the keys we want.
# Get the primary group ID and default shell of Smith dscl . -read /Users/Smith PrimaryGroupID UserShell
To add a resource, we use
dscl . -create. The following
command adds a new user
sudo dscl . -create /Users/belson
If we try to set a password for
sudo passwd belson,
passwd will tell us the
user doesn’t exist. Because
dscl just adds a record to the
data source, but it doesn’t check the integrity. It doesn’t even assign
a UID for
belson. We must assign a UID and a primary group
belson by ourselves, after adding it to the data
# UID 511, GID 20 for example sudo dscl . -create /Users/belson UniqueID 511 sudo dscl . -create /Users/belson PrimaryGroupID 20
belson is a Unix user, and you can set a password
for him using
passwd. However, you still can’t login as
belson, for we don’t assign him a shell.
sudo dscl . -create /Users/belson UserShell /bin/bash
We can login as
belson now, but he doesn’t have a home
directory. We must create the directory and specify it with
sudo dscl . -create /Users/belson NFSHomeDirectory /Users/belson sudo mkdir /User/belson sudo chmod -R belson:staff /User/belson
dscl . -read /Groups/staff will show
that neither the
GroupMembers nor the
GroupMembership attribute has any information about
belson. We have specified his primary group to
staff. But as mentioned before,
check the integrity. Bidirectional relationships must be maintained
To solve the user-group relationship problem, we could use
dseditgroup. The following command adds
staff group, and it takes care of the integrity.2
sudo dseditgroup -o edit -a belson -t user staff
We should make a summary here. To create a user
in the group
staff, we need:
sudo dscl . -create /Users/belson sudo dscl . -create /Users/belson UniqueID 511 sudo dscl . -create /Users/belson PrimaryGroupID 20 sudo dscl . -create /Users/belson UserShell /bin/bash sudo dscl . -create /Users/belson NFSHomeDirectory /Users/belson sudo dseditgroup -o edit -a belson -t user staff sudo mkdir /User/belson sudo chmod -R belson:staff /User/belson
It is painful for a system administrator to type so many commands just to create a new user.
Since Mac OS X 10.10, the
sysadminctl command is
provided. It’s a high-level interface of
sysadminctl in the terminal to see its usage3.
sysadminctl to delete
sudo sysadminctl -deleteUser belson -secure
dscl to check the directory service, we could find
that everything we did is removed.
Now, we add
belson again with
sudo sysadminctl -addUser belson sudo dseditgroup -o edit -a belson -t user staff
If you check the root directory, you will see some traditional Unix
You may also find mac-specified things like
A list of mac-specified directories with their purposes is here4.
|/Library||Contains support files for locally installed applications, among other things.|
|/System||Contains a subdirectory
|/Network||Contains network-mounted Application, Library, and Users directories, as well as a Servers directory that contains directories mounted by the auto mount daemon.|
|/Users||Contains home directories for the users on
the system. The root user’s home directory is
|/Volumes||Contains all visible mounted file systems, including removable media and mounted disk images.|
We could make a list to compare some of them with Linux.
You may be confused here for the difference between
/usr/lib. Which directory should
we put libraries into?
/Library is for macOS-specified software, like the data
of things you download from App Store, and BSD programs shipped with
macOS, like modules of pre-installed Perl and of pre-installed
/usr/local/lib are for Unix
programs installed by yourself.
The init program of macOS is
The launchd program manages two types of services,
LaunchDaemon will be started after the system is booted.
LaunchAgent will be started after a user is logged-in.
If a program needs to be launched after the system is booted, a
.plist file is required to be placed into
If a program needs to be launched after a user logged-in, a
.plist file is required to be placed into
~/Library/LaunchAgents of the user.
launchctl command is used to control services of
# to enable sshd sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist # to disable sshd sudo launchctl unload -w /System/Library/LaunchDaemons/ssh.plist
There is no
/usr/include in macOS. Headers are in the
package of Xcode. Thus your compiler may complain about it. You can run
xcrun --show-sdk-path to print the path6.
$ xcrun --show-sdk-path /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
Then you can use
-isysroot to specify the path for the
compiler, for example:
gcc -isysroot `xcrun --show-sdk-path` hello.c
macOS has no default package manager. Homebrew is the most popular third-party package manager for macOS.
Homebrew is good for many people, but not for one who wants things to go more like common Unix systems. Homebrew assumes you are the only user of the system, but Unix users often share a machine.
Homebrew can’t run as root. If you want to install python, you run
brew install python instead of
sudo brew install python. Homebrew installs packages to
/usr/local. To achieve its sudo-free goal, Homebrew changes
the ownership of
/usr/local to the user who installed
This brings security issues in a shared system. Considering a malware
gcc to infect all the code you compile. Without what
Homebrew does, it must be run as root to achieve its goal, but now, even
it’s run as a normal user, it can write to
Besides the security issue, Homebrew can bring another issue, if
there are multiple administrators in a shared system. Two administrators
both want to use Homebrew to install packages, but
/usr/local/bin can belong to only one of them. So another
administrator will fail. If he or she tries to use Homebrew with
sudo, he or she will also fail. Because Homebrew will check
that if it’s run as root. If it is, Homebrew will refuse to work unless
Homebrew itself belongs to root.
It seems the way to use Homebrew on a shared system is to install
Homebrew by root and use it with
sudo. However, Homebrew
strongly recommends us not to give it the root privilege. The best
practice mentioned in the Homebrew documentation is quoted below.
If you need to run Homebrew in a multi-user environment, consider creating a separate user account especially for use of Homebrew.
This means every time we want to use Homebrew, we must switch the account first.
$ sudo -u brewuser brew install python
If you’re not a fan of Homebrew, there are other package managers.
MacPorts is one of them and it may be more appealing by Unix users. It
sudo to install packages and installs them to
/opt. Thus you can install self-compiled packages to
Andrew. Managing users and groups from the OS X terminal <http://ajmccluskey.com/2015/01/managing-users-and-groups-from-the-os-x-terminal/>↩︎
How to add user to a group from Mac OS X command line? <https://superuser.com/questions/214004/how-to-add-user-to-a-group-from-mac-os-x-command-line>↩︎
Charles S. Edge. Using sysadminctl on macOS <https://krypted.com/mac-os-x/using-sysadminctl-macos/>↩︎
Jepson; Rothman; Rosen. Mac OS X for Unix Geeks.↩︎
Apple Inc. Creating Launch Daemons and Agents <https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html>↩︎
Apple Inc. Xcode 10 Release Notes #3035624 <https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes#3035624>↩︎