Auditing file system metadata, diagnosing file permission discrepancies, and tracking precise file creation timestamps on macOS often requires deeper inspection than conventional tools such as ls -la provide. While developers transitioning from Linux environments often rely on GNU stat, macOS is built atop a BSD UNIX foundation. Consequently, the native macOS stat utility adheres to BSD syntax, utilizing custom format flags and specifiers rather than GNU command-line arguments.
Understanding the native BSD stat implementation is essential for systems administrators, shell script authors, and digital forensic analysts operating on macOS. Unlike GNU stat—which uses parameters like --format=%s—BSD stat employs the -f formatting flag alongside unique conversion specifiers. Crucially, BSD stat provides direct access to APFS and HFS+ file birth times (creation timestamps), inode indices, extended file flags, and raw octal permissions without external dependencies. This guide covers the syntax, specifiers, and practical shell recipes for mastering BSD stat in macOS Terminal.
Key Differences: BSD stat vs GNU stat
Attempting to execute GNU-style flags against the macOS native binary produces immediate syntax errors. The following table contrasts the two implementations:
| Operational Goal | BSD stat (macOS Native) | GNU stat (Linux Coreutils) |
|---|---|---|
| Custom Format String | stat -f "format_specifier" file |
stat --format="format_specifier" file |
| File Size in Bytes | stat -f "%z" file |
stat -c "%s" file |
| Octal Permissions | stat -f "%Op" file or %OLp |
stat -c "%a" file |
| File Birth / Creation Time | stat -f "%SB" file (human-readable) |
stat -c "%w" file |
| Inode Number | stat -f "%i" file |
stat -c "%i" file |
| Symbolic Link Dereference | stat -L -f "..." link |
stat -L -c "..." link |
Comprehensive Format Specifiers in BSD stat
The -f flag accepts a format string composed of percent-escaped specifiers. Formatting modifiers can be inserted between the percent sign and the specifier (such as S for human-readable string output or O for octal values).
| Specifier | Raw Output Description | String Modifier (%S...) Output |
|---|---|---|
%N |
The absolute or relative file name | Quoted or escaped representation |
%z |
File size in exact bytes | Human-readable formatted string (when combined with shell logic) |
%Sp |
Full permission string (e.g., -rwxr-xr-x) |
Standard ls -l style symbolic notation |
%Op / %OLp |
Full raw octal mode (e.g., 100755) |
Standard 3-digit/4-digit octal permissions (e.g., 755) via %OLp |
%u / %Su |
Numeric User ID (UID) of the file owner | User account login name (e.g., admin) |
%g / %Sg |
Numeric Group ID (GID) of the file | Group name (e.g., staff) |
%i |
File system inode record number | Unique decimal identifier on the active APFS volume |
%Sa |
Time of last file access | Standard formatted timestamp string |
%Sm |
Time of last data modification | Standard formatted timestamp string |
%Sc |
Time of last file status/metadata change | Standard formatted timestamp string |
%SB |
Time of file creation (birth time) | Standard formatted timestamp string |
Essential BSD stat Command Recipes for macOS Terminal
Launch Terminal (located in /Applications/Utilities/Terminal.app) or your preferred terminal emulator to execute these targeted diagnostic commands.
1. Printing Human-Readable File Metadata Overview
When invoked with the -x flag, BSD stat produces an expanded summary output that closely resembles traditional UNIX output:
# Produce an expanded multi-line file status report
stat -x document.pdf
The output explicitly details File, Size, FileType, Mode (symbolic and octal), Device, Inode, Links, and exact timestamps for Access, Modify, Change, and Birth.
2. Extracting Octal Permissions for Shell Scripts
To inspect or verify exact permission bits before deploying configuration files or executing backup scripts:
# Extract the exact 3-digit octal permission string (e.g., 644 or 755)
stat -f "%OLp" ~/.ssh/id_ed25519
# Verify SSH private key permissions in an automated script
KEY_PERM=$(stat -f "%OLp" ~/.ssh/id_ed25519)
if [ "$KEY_PERM" != "600" ]; then
echo "Warning: Insecure permissions ($KEY_PERM). Enforcing 600..."
chmod 600 ~/.ssh/id_ed25519
fi
3. Querying APFS File Creation (Birth) Timestamps
One of the most powerful features of APFS and the BSD stat command is accessing true file birth timestamps, which persist across modification events:
# Display file name alongside its original birth timestamp
stat -f "File: %N | Created: %SB" ~/Documents/Report.docx
# Format timestamps into strict ISO-8601 format using the -t flag
stat -t "%Y-%m-%dT%H:%M:%S%z" -f "%N created on: %SB" ~/Documents/Report.docx
4. Auditing Inodes to Track Hard Links and APFS Clones
APFS utilises copy-on-write cloning. To verify whether two files share the exact underlying disk inode or are separate duplicates:
# Compare inodes of two target files
stat -f "File: %N | Inode: %i | Links: %l" fileA.mov fileB.mov
If the decimal numbers in the %i column match, both path names point to the identical filesystem node.
Troubleshooting BSD stat Command Errors
| Observed Error | Underlying Cause | Remediation Step |
|---|---|---|
stat: illegal option -- - |
A GNU long option (e.g., --format or --printf) was passed to the BSD utility. |
Replace GNU parameters with the BSD format flag -f and valid BSD conversion specifiers. |
stat: illegal format character |
A GNU format token (such as %s for size) was used inside the -f string. |
Use BSD equivalent tokens (replace %s with %z; replace %a with %OLp). |
Birth timestamp displays 1970-01-01 |
The file resides on an external exFAT or FAT32 volume that does not record file birth metadata. | File birth tracking requires an APFS or HFS+ native Apple filesystem volume. |
By mastering BSD stat format strings, timestamp flags, and octal specifiers, macOS power users and automation engineers can extract precision filesystem telemetry directly from the command line without installing third-party utilities.