Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

macOS vs Linux vs BSD: Key Differences

If you’re coming to macOS from Linux or BSD, many things will feel familiar—but the differences can be surprising and sometimes frustrating. This chapter catalogs the key differences you’ll encounter, explaining not just what differs but why.

Kernel and System Architecture

Kernel Type

SystemKernelType
macOSXNUHybrid (Mach + BSD)
LinuxLinuxMonolithic (with modules)
FreeBSDFreeBSDMonolithic (with modules)
OpenBSDOpenBSDMonolithic

Impact: macOS uses Mach-O binary format instead of ELF. Tools that work with binaries (nm, objdump, ldd) have different equivalents on macOS.

# Linux: View shared libraries
$ ldd /bin/ls

# macOS: View shared libraries (different tool)
$ otool -L /bin/ls
/bin/ls:
    /usr/lib/libutil.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.61.1)

Init System

SystemInit SystemConfig Format
macOSlaunchdProperty lists (XML/binary)
Linux (modern)systemdUnit files (INI-like)
Linux (traditional)SysVinitShell scripts
FreeBSDrc.dShell scripts

Impact: Service management is completely different on macOS. There’s no systemctl, no /etc/init.d/, no chkconfig.

# Linux (systemd)
$ sudo systemctl start nginx
$ sudo systemctl enable nginx

# macOS (launchd)
$ sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.nginx.plist
$ sudo launchctl enable system/homebrew.mxcl.nginx

Command-Line Tools

BSD vs GNU Commands

macOS ships with BSD versions of common commands. These often have different options than GNU versions:

sed

# GNU sed (Linux): In-place edit
$ sed -i 's/old/new/g' file.txt

# BSD sed (macOS): Requires backup extension (use '' for no backup)
$ sed -i '' 's/old/new/g' file.txt

grep

# GNU grep: Perl regex with -P
$ grep -P '\d{3}-\d{4}' file.txt

# BSD grep (macOS): No -P option, use -E for extended regex
$ grep -E '[0-9]{3}-[0-9]{4}' file.txt

ls

# GNU ls: Color output with --color
$ ls --color=auto

# BSD ls (macOS): Color with -G
$ ls -G

# GNU ls: Human-readable with -h requires -l
$ ls -lh

# BSD ls: -h works without -l (but usually used with -l anyway)
$ ls -lh

date

# GNU date: Specific date formatting
$ date -d "2024-01-15" +%s

# BSD date (macOS): Different syntax
$ date -j -f "%Y-%m-%d" "2024-01-15" +%s

stat

# GNU stat
$ stat --format="%s" file.txt

# BSD stat (macOS)
$ stat -f "%z" file.txt
# GNU readlink: -f to canonicalize
$ readlink -f /path/to/symlink

# BSD readlink (macOS): No -f, but realpath exists (macOS 12.3+)
$ realpath /path/to/symlink
# Or for older macOS:
$ python3 -c "import os; print(os.path.realpath('/path/to/symlink'))"

macOS-Specific Commands

macOS includes commands with no Linux/BSD equivalent:

# Copy to clipboard
$ echo "Hello" | pbcopy
$ pbpaste

# Open files with default application
$ open file.pdf
$ open -a Safari https://apple.com
$ open .  # Open current directory in Finder

# Spotlight search
$ mdfind "search term"
$ mdfind -name "filename"
$ mdfind "kMDItemContentType == 'public.jpeg'"

# Text-to-speech
$ say "Hello, world"

# Manage system preferences
$ open "x-apple.systempreferences:"

# Screen capture
$ screencapture -i screenshot.png

# Airport (Wi-Fi) utility
$ /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s

# Disk utility
$ diskutil list
$ diskutil info disk0

Network Commands

Networking tools differ significantly:

# Linux: Modern networking
$ ip addr show
$ ip route
$ ss -tuln

# macOS: BSD networking
$ ifconfig
$ netstat -rn
$ netstat -an | grep LISTEN

Note: ip doesn’t exist on macOS (unless installed via Homebrew). macOS uses traditional BSD tools like ifconfig, netstat, and route.

# Linux: Network manager
$ nmcli device status

# macOS: networksetup
$ networksetup -listallhardwareports
$ networksetup -getinfo "Wi-Fi"

Filesystem Differences

Filesystem Types

SystemDefault FSFeatures
macOSAPFSSnapshots, encryption, space sharing, clones
Linuxext4 / XFS / BtrfsVaries by filesystem
FreeBSDZFS / UFSZFS has similar features to APFS

Case Sensitivity

macOS is case-insensitive but case-preserving by default:

# On default macOS filesystem:
$ touch File.txt
$ ls file.txt
File.txt           # Finds it! Different from Linux

This can cause issues with Git repositories from case-sensitive systems.

Filesystem Hierarchy

Key differences from the Filesystem Hierarchy Standard (FHS):

PurposeLinux/BSD FHSmacOS
Applications/usr/bin, /opt/Applications
System config/etc/etc (Unix) + /Library/Preferences (macOS)
User config~/.config~/Library
User dataVarious~/Documents, ~/Library/Application Support
Temp files/tmp/tmp → /private/tmp
Variable data/var/var → /private/var
System libraries/usr/lib/usr/lib + /System/Library/Frameworks
Third-party/opt, /usr/local/usr/local, /opt/homebrew (ARM)

Extended Attributes

macOS uses extended attributes heavily:

# View extended attributes
$ xattr file.txt
com.apple.quarantine

# List with values
$ xattr -l file.txt
com.apple.quarantine: 0083;5f4a7c14;Safari;...

# Remove quarantine attribute
$ xattr -d com.apple.quarantine file.txt

# Clear all attributes
$ xattr -c file.txt

Linux has extended attributes too, but they’re less pervasive:

# Linux extended attributes
$ getfattr -d file.txt
$ setfattr -n user.comment -v "test" file.txt

Resource Forks and Metadata

macOS preserves metadata when copying files:

# macOS: Copy with metadata
$ cp -p file.txt dest/          # Preserves basic metadata
$ ditto source/ dest/           # Preserves everything including resource forks

# Problem: copying to non-HFS+/APFS filesystems
$ cp file.txt /Volumes/USB_FAT32/
# Creates file.txt and ._file.txt (AppleDouble file)

Those ._* files you see on USB drives? That’s macOS preserving metadata on filesystems that don’t support it natively.

Package Management

No Native Package Manager

Unlike most Linux distributions and BSD systems, macOS doesn’t include a built-in package manager for third-party software:

SystemNative Package Manager
macOSNone (uses App Store for GUI apps)
Debian/Ubuntuapt
Red Hat/Fedoradnf/yum
Archpacman
FreeBSDpkg
OpenBSDpkg_add

Solutions for macOS:

# Homebrew (most popular)
$ brew install wget

# MacPorts (alternative)
$ sudo port install wget

User and Permission Differences

User IDs

UserLinuxmacOS
rootUID 0UID 0
First userUID 1000UID 501
NobodyUID 65534UID -2

Groups

macOS has different default groups:

$ id
uid=501(david) gid=20(staff) groups=20(staff),12(everyone),61(localaccounts),...

The primary group for users is staff (GID 20), not a user-specific group.

System Integrity Protection (SIP)

macOS restricts what even root can do:

# This fails even as root (SIP protected):
$ sudo rm /System/Library/CoreServices/Finder.app
rm: /System/Library/CoreServices/Finder.app: Operation not permitted

# Check SIP status
$ csrutil status
System Integrity Protection status: enabled.

Linux and BSD have no equivalent to SIP—root can do anything.

Sudo Configuration

macOS doesn’t use /etc/sudoers by default for most permissions. Instead, it uses admin group membership:

# Check who can sudo
$ grep -E "^%admin|^%wheel" /etc/sudoers
%admin		ALL = (ALL) ALL

Process and System Management

Process Listing

# Both work on macOS:
$ ps aux                    # BSD syntax
$ ps -ef                    # POSIX syntax

# Linux-specific options don't work:
$ ps --forest              # Error on macOS

System Information

# Linux
$ cat /proc/cpuinfo
$ free -h
$ lsb_release -a

# macOS (no /proc filesystem)
$ sysctl -n machdep.cpu.brand_string
$ vm_stat                   # Memory (in pages, not bytes)
$ sw_vers                   # macOS version

Signals

Signal numbers can differ:

# Check signal numbers
$ kill -l

Most common signals (SIGTERM=15, SIGKILL=9, SIGHUP=1) are the same.

Development Environment

Compiler

# Linux (usually GCC)
$ gcc --version
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0

# macOS (Clang masquerading as gcc)
$ gcc --version
Apple clang version 15.0.0 (clang-1500.3.9.4)

The gcc command on macOS is actually Clang. This usually doesn’t matter, but some software with GCC-specific features may need adjustment.

Libraries

# Linux: Shared library extension
libfoo.so, libfoo.so.1, libfoo.so.1.0.0

# macOS: Shared library extension
libfoo.dylib, libfoo.1.dylib, libfoo.1.0.0.dylib

# Linux: Find library
$ ldconfig -p | grep libssl
$ ldd /usr/bin/openssl

# macOS: Find library
$ otool -L /usr/bin/openssl

Library Paths

# Linux
$ echo $LD_LIBRARY_PATH
$ cat /etc/ld.so.conf

# macOS
$ echo $DYLD_LIBRARY_PATH           # Runtime
$ echo $DYLD_FALLBACK_LIBRARY_PATH  # Fallback

Virtualization and Containers

Docker

# Linux: Docker runs natively
$ docker run alpine echo "Hello"

# macOS: Docker runs in a Linux VM
$ docker run alpine echo "Hello"
# (Actually runs in a hypervisor-backed Linux VM)

Docker Desktop on macOS uses a Linux virtual machine because containers are a Linux kernel feature.

Native Virtualization

# macOS: Virtualization.framework (Apple Silicon) or Hypervisor.framework
# No direct CLI, used by apps like UTM, Parallels, Docker Desktop

# Linux: KVM
$ virsh list --all

Summary Table

FeaturemacOSLinuxFreeBSD
KernelXNU (hybrid)Linux (monolithic)FreeBSD (monolithic)
Initlaunchdsystemd (usually)rc.d
Package mgrHomebrew (3rd party)apt/dnf/pacmanpkg
Shell defaultzshbash (usually)sh/tcsh
FilesystemAPFSext4/XFS/BtrfsZFS/UFS
Case sensitiveNo (default)YesConfigurable
Binary formatMach-OELFELF
CommandsBSDGNUBSD
Firewallpfiptables/nftablespf/ipfw
Root restrictionSIPSELinux/AppArmorsecurelevel

Understanding these differences helps you translate your Unix knowledge to macOS effectively. When something doesn’t work as expected, check whether it’s a BSD vs GNU difference, a filesystem assumption, or a macOS-specific security feature.