umask — Default file permission mask, 022 vs 002 vs 077, group-shared vs private defaults across all 5 shells
Equivalents in every shell
umask 022`umask` is a SHELL BUILTIN (not an external binary) — it sets the mask that newly-created files INHERIT. The mask is the bits REMOVED from the default (666 for files, 777 for dirs): umask 022 → files 644, dirs 755. Run `umask` with no args to print the current mask in octal; `umask -S` symbolic form (`u=rwx,g=rx,o=rx`).
umask 022umask 022Fish has the same builtin. To make it persistent: add `umask 022` to `~/.config/fish/config.fish`. Fish also accepts symbolic form: `umask u=rwx,g=rx,o=rx`.
# Windows has NO umask — ACL inheritance from the parent directory determines new-file permissions instead. To change defaults: edit the parent dir ACL with inheritable ACEs (icacls /grant Users:(OI)(CI)(RX) /t)pwsh on Linux/macOS uses the underlying umask (subprocesses inherit it via the process's file-creation mask field — pwsh itself has no umask cmdlet, but `[System.Convert]::ToInt32("022", 8)` then a P/Invoke to `umask(3)` is doable). On Windows, the umask concept doesn't exist; new files inherit DACLs from the parent directory via ContainerInherit/ObjectInherit flags on the parent's ACEs.
rem cmd has no umask equivalent. Inheritance-based: icacls dir /inheritance:eNo native command. The closest concept is enabling/disabling ACL inheritance on a directory: `icacls dir /inheritance:e` (enable — child files inherit), `icacls dir /inheritance:d` (disable but copy current ACEs), `icacls dir /inheritance:r` (remove all inherited ACEs). For pwsh fine-grained control: `Get-Acl dir | Set-Acl ...`.
Worked examples
Show current umask
umaskumask# no equivalent on Windows; on Linux/macOS pwsh: & sh -c "umask"rem no equivalentSet umask to 077 (owner-only, lock out group and other)
umask 077umask 077# Windows: icacls "$HOME" /inheritance:r /grant:r "${env:USERNAME}:(OI)(CI)F"icacls "%USERPROFILE%" /inheritance:r /grant:r "%USERNAME%":(OI)(CI)FSet umask in symbolic form (group + other read-only)
umask u=rwx,g=rx,o=rxumask u=rwx,g=rx,o=rx# no equivalent — Windows uses ACLsrem no equivalentGotchas
- umask is SUBTRACTIVE — the value is what gets REMOVED from the default. Default for files is 666 (rw-rw-rw-), for dirs is 777 (rwxrwxrwx). umask 022 means "remove write for group + other" → files end up 644, dirs 755. Common values: `022` (default on most distros — files 644, dirs 755), `002` (group-writable — files 664, dirs 775 — for team shared dirs), `077` (owner-only — files 600, dirs 700 — for sensitive data), `027` (group readable, other locked out — files 640, dirs 750 — common server config).
- umask is PER-SHELL-PROCESS — setting it in your terminal does NOT affect daemons, cron jobs, systemd units, or files extracted from tar. To make it default for your interactive shells: add `umask 022` to `~/.bashrc` / `~/.zshrc` / `~/.config/fish/config.fish`. To make it default for SYSTEM services: edit `/etc/login.defs` `UMASK 022` (sets the default for all users via PAM), or per-systemd-unit add `UMask=0022` to the [Service] section. Cron jobs use their own umask — set with `0 * * * * umask 022 && /usr/local/bin/job`.
- umask does NOT apply to `cp -p` / `cp -a` / `tar -x` / `rsync -a` — those preserve the SOURCE file's permissions, bypassing umask entirely. So extracting a tar of files that were 0600 elsewhere creates 0600 files locally regardless of your umask. `cp` without `-p` DOES use umask. To force umask on tar extract: `tar xf archive.tar --no-same-permissions` (then permissions = umask-computed default). For rsync: `rsync --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r` (D=directory, F=file).
- Setting umask to 0 (or anything < 002) is a SECURITY HOLE — `umask 0` makes every new file 666 (world-writable). Even umask 002 (group-writable default) is risky on multi-user systems where the user's primary group is the shared `users` group (Debian default). Modern distros use user-private groups (each user's primary group is their own one-member group), making `002` safe. Check `id` — if your gid name matches your username, you have a private group and `002` is OK; if you're in a shared primary group, use `022` or `027`.
- Windows has NO umask — the concept doesn't exist because Windows uses ACL INHERITANCE (the parent directory's ACEs propagate to new children via OI/CI flags). To get "umask 077-equivalent" behaviour on Windows: set the parent directory ACL to grant FULL access only to the current user, with `(OI)(CI)` inheritance flags. Files created in that directory inherit the same locked-down ACL. `icacls $HOME /inheritance:r /grant:r "${env:USERNAME}:(OI)(CI)F"` is the rough equivalent of `umask 077` for the user's home directory — but applies retroactively to existing files too, unlike umask which is purely forward-looking.
- Files are NEVER created with the X bit set by the shell — even with `umask 000`. The kernel masks X off for FILES at creation regardless of the umask; only DIRECTORIES get X by default. The execute bit must be set explicitly with `chmod +x` after creation. Common surprise: developers writing `umask 000; touch ./script.sh` then wondering why the file is `rw-rw-rw-` instead of `rwxrwxrwx` — that's the kernel-side X mask, not umask.
- macOS Finder respects umask for the user's shell but IGNORES it for files copied through the Finder GUI — Finder uses macOS-internal defaults (typically the parent directory's extended-attribute defaults). For predictable permissions cross-process (shell + GUI + AppleScript + automator), use `chmod` after creation instead of relying on umask. Same caveat applies to many Linux desktop environments' file managers — GNOME Files / Dolphin / Thunar may also ignore umask under certain operations (drag-drop copy across filesystems with different default-perms semantics).