Skip to content
shellmap

getfaclShow extended POSIX ACLs (xattrs, mask, default-ACL). icacls / Get-Acl Windows across all 5 shells

Equivalents in every shell

Bashunix
getfacl file.txt

From `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.

Zshunix
getfacl file.txt
Fishunix
getfacl file.txt
PowerShellwindows
(Get-Acl file.txt).Access | Format-Table IdentityReference, FileSystemRights, AccessControlType, IsInherited -AutoSize

Windows-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.

cmd.exewindows
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

Bash
getfacl file.txt
Fish
getfacl file.txt
PowerShell
(Get-Acl file.txt).Access
cmd.exe
icacls file.txt

Show only the extended (non-POSIX-base) ACL entries

Bash
getfacl --absolute-names --skip-base file.txt
Fish
getfacl --absolute-names --skip-base file.txt
PowerShell
(Get-Acl file.txt).Access | Where-Object { -not $_.IsInherited -and $_.IdentityReference -notin "BUILTIN\Administrators","NT AUTHORITY\SYSTEM" }
cmd.exe
icacls file.txt | findstr /v "Administrators SYSTEM"

Show the default ACL (inherited by NEW children) on a directory

Bash
getfacl -d dir/
Fish
getfacl -d dir/
PowerShell
(Get-Acl dir).Access | Where-Object { $_.InheritanceFlags -ne "None" }
cmd.exe
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.

WSL & PowerShell Core notes

pwshpwsh 7 on Linux: no Get-Acl equivalent for POSIX ACLs — shell out to `getfacl`. pwsh on Windows: `Get-Acl` returns a `FileSecurity` object with NTFS ACLs (entirely different model). For cross-platform scripts: `if ($IsLinux) { & getfacl $file } else { Get-Acl $file }`.
WSLWSL Linux `getfacl` works on the WSL filesystem (`~`, `/home`, `/`). On Windows-mounted paths (`/mnt/c/...`) `getfacl` may show only the POSIX-mode-bits view of the underlying NTFS ACL — the rich Windows DACL is NOT translated to POSIX ACL semantics. To read NTFS ACLs of `/mnt/c/...` from WSL, call `pwsh.exe -Command "Get-Acl C:\path\file" via interop, not `getfacl`.

Related commands