getfacl — Show extended POSIX ACLs (xattrs, mask, default-ACL). icacls / Get-Acl Windows across all 5 shells
Equivalents in every shell
getfacl file.txtFrom `acl` package (`apt install acl` / `dnf install acl` — installed by default on Ubuntu 18.04+, Fedora, RHEL 7+). Reads the `system.posix_acl_access` xattr (and `system.posix_acl_default` for default-ACL on directories). Output format: `# file:`, `# owner:`, `# group:` header, then `user::rwx` / `group::r-x` / `other::r--` (the standard POSIX bits), plus any explicit `user:alice:rwx` / `group:devs:rx` entries, plus a `mask::` line if extended entries exist.
getfacl file.txtgetfacl file.txt(Get-Acl file.txt).Access | Format-Table IdentityReference, FileSystemRights, AccessControlType, IsInherited -AutoSizeWindows-only cmdlet. On Linux/macOS pwsh 7, there is no `Get-Acl` for POSIX ACLs — fall back to `& getfacl file.txt` via the system shell. Windows uses DACL (Discretionary ACL — grants/denies) — a fundamentally different model than POSIX.1e ACL. For audit entries (SACL), use `(Get-Acl file -Audit).Audit` and run as Administrator.
icacls file.txt`icacls FILE` prints the DACL in one-line-per-principal compact form: `Everyone:(R)` (read), `BUILTIN\Administrators:(F)` (full control). Inheritance flags shown as `(OI)` / `(CI)` / `(I)` prefixes. There is NO POSIX-ACL on Windows — files have NTFS ACLs which are an entirely different model.
Worked examples
Show the full ACL of a file
getfacl file.txtgetfacl file.txt(Get-Acl file.txt).Accessicacls file.txtShow only the extended (non-POSIX-base) ACL entries
getfacl --absolute-names --skip-base file.txtgetfacl --absolute-names --skip-base file.txt(Get-Acl file.txt).Access | Where-Object { -not $_.IsInherited -and $_.IdentityReference -notin "BUILTIN\Administrators","NT AUTHORITY\SYSTEM" }icacls file.txt | findstr /v "Administrators SYSTEM"Show the default ACL (inherited by NEW children) on a directory
getfacl -d dir/getfacl -d dir/(Get-Acl dir).Access | Where-Object { $_.InheritanceFlags -ne "None" }icacls dir /t /q | findstr "(OI)\|(CI)"Gotchas
- `ls -l` does NOT show extended ACLs by default — only a tiny `+` indicator appended to the mode column (`-rw-r--r--+ 1 alice ...`) tells you an ACL exists. Without the `+`, `ls -l` is the full picture. With the `+`, always run `getfacl` to see the truth. macOS shows `@` for xattrs (different from ACLs) or `+` for ACLs — `ls -le` decodes them. The trap: scripts that audit "are these files locked down?" by parsing `ls -l` alone MISS extended ACLs that grant extra access — a file showing `-rw-------` might still have `user:web:r--` granted via setfacl.
- The `mask::` line silently caps effective permissions. When a file has extended entries, `getfacl` shows a `mask::rwx` line — the mask ANDs with every explicit user/group entry to give the EFFECTIVE permissions. So `user:alice:rwx` + `mask::r--` → alice only gets `r--` in practice. `getfacl` prints `#effective:r--` next to each masked entry. CRITICAL gotcha: `chmod g+w file` MODIFIES THE MASK, NOT the group entry. So after `setfacl -m u:alice:rwx file && chmod g-w file`, alice no longer has write — the chmod silently capped her. Always read the mask line before debugging "but I granted alice write — why is it failing?"
- macOS does NOT have `getfacl` — APFS / HFS+ use NFSv4-style ACLs, not POSIX.1e. macOS equivalent: `ls -le file.txt` (the `e` flag shows ACLs in `0: group:everyone deny delete` format), `chmod +a "user:alice allow read" file` to add. The two models are NOT interchangeable: POSIX ACLs are unordered + additive; NFSv4 ACLs are ORDERED with first-match-wins + can have DENY entries. Files SMB-shared between Linux and macOS collapse extended ACLs to mode bits in transit.
- `getfacl --absolute-names --skip-base file` outputs ONLY the extended (beyond-POSIX-base) entries. Empty output means there's no extended ACL — `chmod` mode bits are the full picture, safe to ignore. Use this in scripts to QUICKLY detect "does this file have an ACL?" without parsing the full output: `if getfacl --skip-base -p file 2>/dev/null | grep -q .; then echo "has ACL"; fi`.
- ACLs are stored in xattrs and CAN BE LOST. `cp` without `-p` (or `--preserve=all`) drops them. `tar` without `--xattrs` (default OFF on many tar versions) silently strips them. `rsync` without `-X` (xattrs) drops them. Network filesystems vary: NFSv3 has NO concept of POSIX ACLs (they're local-only); NFSv4 has its own ACL model that may or may not round-trip POSIX ACLs cleanly. Always test backup/restore of ACL-protected files BEFORE relying on them in production. `cp --preserve=all`, `tar --acls --xattrs`, `rsync -aAX` are the preservation-aware forms.