umask 命令详解与参数实测(Ubuntu 22.04)
以 Ubuntu 22.04(bash 5.1.16)实测逐项讲解 umask:-S/-p 与八进制符号两种写法、掩码计算 0666&~022=644、022/077/002 三档实测、只影响当前 shell 与退出失效、login.defs 默认值来源、与 chmod/chown 职责对比及 HOME_MODE 联动。
umask 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 umask 的查看与设置——无参数查看(八进制 0022)、
-S符号输出、八进制与符号两种设置写法及其等价性(0022/022/22/u=rwx,g=rx,o=rx)、掩码计算原理(0666&~022=644、0777&~022=755)、022/077/002 三档实测、只影响当前 shell(子 shell 继承与退出失效)、对已有文件无影响、系统默认值来源(/etc/login.defs 的 UMASK 与 HOME_MODE)、-p可复用输出与非法值报错等,全部命令与回显已在 Ubuntu 22.04(bash 5.1.16)实测通过。
一、环境信息
本文所有命令均在以下环境实测,回显逐字照抄:
- 操作系统:Ubuntu 22.04.5 LTS(
PRETTY_NAME="Ubuntu 22.04.5 LTS") - 内核架构:x86_64
- Shell:GNU bash 5.1.16(1)-release;umask 是 bash 的内置命令(无独立可执行文件、无 --version)
- 执行身份:root,会话默认掩码 0022
- 演示数据目录:
/root/demo/umask/(含 f022.txt、d022、f077.txt、d077、shared.txt、secret.log 等实测产物) - 关联演示用户:u4m1、u4m2(家目录权限联动实测,用后已删)
💡 说明:umask 属于 POSIX shell 规范的内建能力,bash、dash、zsh 都实现它且行为一致;本文全部在 bash 下实测。
二、命令概览
2.1 语法与测试数据
umask 设置(或查看)文件创建掩码:新建文件、目录时,系统先给一个最大起点(常规为文件 0666、目录 0777),再按掩码「减去」对应权限位,得到实际权限。语法(来自实测 help umask 首行):
umask: umask [-p] [-S] [mode]
- 无参数:打印当前掩码(八进制);
-S:以符号形式打印当前掩码;-p:以「可再次作为输入」的完整命令形式打印;mode:八进制数字(如 022、077)或符号模式串(如 u=rwx,g=rx,o=rx)。
本文测试数据约定:演示文件统一建在 /root/demo/umask/,用 touch/mkdir 触发创建,用 stat -c '%a %n' 读取数字权限,每档掩码实测后给出真实产物。
💡 技术拓展:umask 与 chmod、chown 常被混为一谈,三者职责对比——
工具 作用对象 生效时机 典型用途 umask 将来新建的文件/目录(权限减法起点) 创建那一刻 批量收紧/放开新建文件的最宽权限 chmod 已存在的文件/目录 立即 精确修改存量权限 chown 文件/目录的属主与属组 立即 移交所有权 一句话分工:umask 决定「出生权限」,chmod 负责事后修补,chown 管归属——三者配合见 4.4。
2.2 help umask 全量输出(逐行照抄)
umask 是 bash 内置命令,没有 --help 选项,内置帮助用 help umask 查看。完整实测输出:
$ help umask
umask: umask [-p] [-S] [mode]
Display or set file mode mask.
Sets the user file-creation mask to MODE. If MODE is omitted, prints
the current value of the mask.
If MODE begins with a digit, it is interpreted as an octal number;
otherwise it is a symbolic mode string like that accepted by chmod(1).
Options:
-p if MODE is omitted, output in a form that may be reused as input
-S makes the output symbolic; otherwise an octal number is output
Exit Status:
Returns success unless MODE is invalid or an invalid option is given.
帮助原文给出两条关键规则:mode 以数字开头按八进制解释,否则按 chmod(1) 风格的符号模式解释;只有 mode 非法或选项非法时才返回非零。
2.3 版本信息
umask 无独立版本,随 shell 走。实测 bash 版本与内置属性:
$ bash --version | head -1
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
$ echo $BASH_VERSION
5.1.16(1)-release
$ type umask
umask is a shell builtin
💡 要点:type umask 返回 shell builtin——它不是 /usr/bin 下的程序,因此没有 --version、没有 man 手册页(manual 记录在 bash(1) 的 SHELL BUILTIN COMMANDS 章节),查用法用 help umask。
三、参数逐项实测
3.1 无参数:查看当前掩码(八进制 0022)
umask
umask -S
实测回显:
$ umask
0022
$ umask -S
u=rwx,g=rx,o=rx
💡 要点:
- root 会话默认掩码 0022(四位八进制:首位是 setuid/setgid/sticky 特殊位,常规恒为 0;后三位依次对应用户/组/其他被「减掉」的权限)。
- 同一掩码的两种视图:八进制
0022与符号u=rwx,g=rx,o=rx一一对应——符号视图展示的是允许保留的位,八进制展示的是要减掉的位(对照 3.6 的符号设置语义)。
3.2 mode 八进制设置:umask 022(新文件 644、新目录 755)
umask 022
umask
touch /root/demo/umask/f022.txt && mkdir /root/demo/umask/d022
ls -l /root/demo/umask/f022.txt
ls -ld /root/demo/umask/d022
stat -c '%a %n' /root/demo/umask/f022.txt /root/demo/umask/d022
实测回显:
$ umask 022
$ umask
0022
$ umask -S
u=rwx,g=rx,o=rx
$ touch /root/demo/umask/f022.txt && mkdir /root/demo/umask/d022
$ ls -l /root/demo/umask/f022.txt
-rw-r--r-- 1 root root 0 Oct 15 09:24 /root/demo/umask/f022.txt
$ ls -ld /root/demo/umask/d022
drwxr-xr-x 2 root root 4096 Oct 15 09:24 /root/demo/umask/d022
$ stat -c '%a %n' /root/demo/umask/f022.txt /root/demo/umask/d022
644 /root/demo/umask/f022.txt
755 /root/demo/umask/d022
💡 要点:掩码 022 下新文件 644(rw-r--r--)、新目录 755(rwxr-xr-x)——这正是 Linux 世界最经典的默认权限组合,计算过程见 3.5。
3.3 mode 八进制设置:umask 077(600/700)与对已有文件无影响
umask 077
umask
umask -S
touch /root/demo/umask/f077.txt && mkdir /root/demo/umask/d077
ls -l /root/demo/umask/f077.txt
ls -ld /root/demo/umask/d077
stat -c '%a %n' /root/demo/umask/f077.txt /root/demo/umask/d077
stat -c '%a %n' /root/demo/umask/f022.txt
实测回显:
$ umask 077
$ umask
0077
$ umask -S
u=rwx,g=,o=
$ touch /root/demo/umask/f077.txt && mkdir /root/demo/umask/d077
$ ls -l /root/demo/umask/f077.txt
-rw------- 1 root root 0 Oct 15 09:24 /root/demo/umask/f077.txt
$ ls -ld /root/demo/umask/d077
drwx------ 2 root root 4096 Oct 15 09:24 /root/demo/umask/d077
$ stat -c '%a %n' /root/demo/umask/f077.txt /root/demo/umask/d077
600 /root/demo/umask/f077.txt
700 /root/demo/umask/d077
$ stat -c '%a %n' /root/demo/umask/f022.txt
644 /root/demo/umask/f022.txt
💡 要点:掩码 077 下新文件 600、新目录 700(仅属主可读写/进入),敏感数据落地的标准配置;⚠️ 注意最后一行——此前创建的 f022.txt 仍是 644,umask 只在创建瞬间起作用,对存量文件零影响,修补必须用 chmod(见 4.4 实测)。
3.4 掩码计算原理:0666&~022 与 0777&~022(实证)
新文件起点 0666、新目录起点 0777,实际权限 = 起点 AND(掩码按位取反)。用 shell 八进制算术逐式验证:
printf '%04o\n' $(( 0666 & ~0022 ))
printf '%04o\n' $(( 0777 & ~0022 ))
printf '%04o\n' $(( 0666 & ~0077 ))
printf '%04o\n' $(( 0777 & ~0077 ))
实测回显:
$ printf '%04o\n' $(( 0666 & ~0022 ))
0644
$ printf '%04o\n' $(( 0777 & ~0022 ))
0755
$ printf '%04o\n' $(( 0666 & ~0077 ))
0600
$ printf '%04o\n' $(( 0777 & ~0077 ))
0700
逐位拆解(以 022 为例,r=4、w=2、x=1):
| 对象 | 起点 | 掩码 | 起点 AND ~掩码 | 实测结果 |
|---|---|---|---|---|
| 新文件 | 0666(rw-rw-rw-) | 0022(-----w--w-) | 0644(rw-r--r--) | 644 ✓ |
| 新目录 | 0777(rwxrwxrwx) | 0022 | 0755(rwxr-xr-x) | 755 ✓ |
| 新文件 | 0666 | 0077 | 0600(rw-------) | 600 ✓ |
| 新目录 | 0777 | 0077 | 0700(rwx------) | 700 ✓ |
💡 要点:掩码是减法——掩码里为 1 的位在结果中必为 0。这也解释了「新文件默认没有执行位」:起点是 0666 而不是 0777,执行位需要显式 chmod(或程序自身带 x 语义的创建调用),与掩码无关。
3.5 -S:符号输出与符号写法设置
-S 打印符号掩码;符号串也可以直接设置掩码,注意语义与 chmod 相反——符号串写的是允许保留的位:
umask 022 && umask -S
umask u=rwx,g=rx,o=rx && umask
umask u=rwx,g=,o= && umask
实测回显:
$ umask 022 && umask -S
u=rwx,g=rx,o=rx
$ umask u=rwx,g=rx,o=rx && umask
0022
$ umask u=rwx,g=,o= && umask
0077
💡 要点:u=rwx,g=,o=(组与其他一个位都不留)等价于 077;符号语义「写允许位」与八进制语义「写减除位」互为补码,混用时最容易在这里翻车——拿不准就设完 umask 回显复核。
3.6 写法等价:0022 / 022 / 22
三种八进制写法实测等价(bash 都按八进制解析、按四位显示):
umask 0022 && umask
umask 22 && umask
umask 0022 && umask
实测回显:
$ umask 0022 && umask
0022
$ umask 22 && umask
0022
$ umask 0022 && umask
0022
💡 要点:umask 的显示恒为四位(0022),设置时可写 0022、022 甚至 22;但脚本里建议统一写四位 0022——在 $(( )) 算术等上下文里「前导 0 即八进制」的规则一致,写全可避免歧义。
3.7 -p:可复用输出形式(带 mode 时不回显)
umask 0022 && umask
umask -p
umask -p 077; echo rc=$?
umask
实测回显:
$ umask 0022 && umask
0022
$ umask -p
umask 0022
$ umask -p 077; echo rc=$?
rc=0
$ umask
0077
💡 要点:umask -p 输出 umask 0022,可直接粘回脚本复用;⚠️ 实测带 mode 时(umask -p 077)不打印任何内容但照样生效(rc=0,随后 umask 显示 0077)——把它当「静默设置」用容易漏复核,建议设置后总跟一句 umask 确认。
3.8 非法值报错与失败不改值
非法八进制、非法符号串都会报错且 rc=1,当前掩码保持不变(交互式捕获,报错前缀为 bash:):
$ umask 089; echo rc=$?
bash: umask: 089: octal number out of range
rc=1
$ umask abc; echo rc=$?
bash: umask: `b': invalid symbolic mode operator
rc=1
实测补充(脚本上下文中的同一组命令,验证失败不改值):
$ umask -p 077
$ umask 089; echo rc=$?
/root/umask-test3.sh: line 3: umask: 089: octal number out of range
rc=1
$ umask abc; echo rc=$?
/root/umask-test3.sh: line 3: umask: `b': invalid symbolic mode operator
rc=1
$ umask; echo rc=$?
0077
rc=0
💡 要点:两次失败设置后掩码仍是此前设的 0077——非法 mode 不产生半生效状态;abc 的报错把 a 当成了 who、b 当成了运算符,提示信息直指第一个非法字符。非交互执行时 bash 报错带「来源文件: 行号」前缀,交互式则是 bash: 前缀。
3.9 作用域:只影响当前 shell(子 shell 继承、退出失效)
umask 是进程属性:子 shell 从父 shell 继承当前值,子 shell 里的修改随其退出消失,父 shell 不受影响。父 022 / 子 077 的干净对照:
umask 022 && umask
bash -c 'umask 077; touch /root/demo/umask/fsub2.txt; stat -c %a /root/demo/umask/fsub2.txt'
umask
touch /root/demo/umask/fparent2.txt && stat -c '%a %n' /root/demo/umask/fparent2.txt
bash -c 'umask 077'
umask
实测回显:
$ umask 022 && umask
0022
$ bash -c 'umask 077; touch /root/demo/umask/fsub2.txt; stat -c %a /root/demo/umask/fsub2.txt'
600
$ umask
0022
$ touch /root/demo/umask/fparent2.txt && stat -c '%a %n' /root/demo/umask/fparent2.txt
644 /root/demo/umask/fparent2.txt
$ bash -c 'umask 077'
$ umask
0022
💡 要点:
- 子 shell(
bash -c、脚本)里设 077 后建文件得 600;父 shell 掩码仍是 0022,父 shell 建的文件是 644——继承是单向向下的。 - 最后一组:子 shell 设完 077 就退出,什么也没留下,父 shell 依旧 0022——「退出失效」的实测形态。要跨会话持久化,把
umask 022写进~/.bashrc或/etc/profile.d/*.sh(见 3.10)。
3.10 系统默认值来源:/etc/login.defs 与 /etc/profile 实况
登录会话的默认掩码由 PAM/shadow 体系与 shell 配置共同决定。实测关键配置:
grep -n 'UMASK' /etc/login.defs
grep -n 'HOME_MODE' /etc/login.defs
grep -rn 'umask' /etc/profile /etc/profile.d/ /etc/bash.bashrc 2>/dev/null | head -8
实测回显:
$ grep -n 'UMASK' /etc/login.defs
131:# UMASK Default "umask" value.
135:# UMASK is the default umask value for pam_umask and is used by
137:# 022 is the "historical" value in Debian for UMASK
142:# If USERGROUPS_ENAB is set to "yes", that will modify this UMASK default value
151:UMASK 022
155:# If HOME_MODE is not set, the value of UMASK is used to create the mode.
$ grep -n 'HOME_MODE' /etc/login.defs
153:# HOME_MODE is used by useradd(8) and newusers(8) to set the mode for new
155:# If HOME_MODE is not set, the value of UMASK is used to create the mode.
156:HOME_MODE 0750
$ grep -rn 'umask' /etc/profile /etc/profile.d/ /etc/bash.bashrc 2>/dev/null | head -8
💡 要点:
/etc/login.defs的UMASK 022(第 151 行)是 pam_umask 与 shadow 工具的默认值来源——这就是 root 会话 0022 的出处;注释第 142 行还说明USERGROUPS_ENAB yes(每用户私有组模型)会在此基础上调整普通用户的实际掩码,因此普通用户登录后常见 0002(组可写,配合私有组正好安全)。HOME_MODE 0750(第 156 行)优先级高于 UMASK,专管 useradd/newusers 建家目录的权限(对照《useradd 命令详解与参数实测(Ubuntu 22.04)》篇 3.2 的drwxr-x---)。- 本环境
/etc/profile、/etc/profile.d/、/etc/bash.bashrc中均无 umask 配置(grep 无输出)——shell 会话的 0022 是从父进程一路继承下来的,而非 profile 显式设置;要全局定制应在 profile.d 落一条umask 022。
3.11 与 useradd 的联动:-K UMASK 不改家目录、-K HOME_MODE 生效
掩码体系与建号工具的边界实测(-K 覆盖 /etc/login.defs 键值):
useradd -m -K UMASK=077 u4m1
ls -ld /home/u4m1
useradd -m -K HOME_MODE=0700 u4m2
ls -ld /home/u4m2
userdel -r u4m1; userdel -r u4m2
实测回显:
$ useradd -m -K UMASK=077 u4m1
$ ls -ld /home/u4m1
drwxr-x--- 2 u4m1 u4m1 4096 Oct 15 09:24 /home/u4m1
$ useradd -m -K HOME_MODE=0700 u4m2
$ ls -ld /home/u4m2
drwx------ 2 u4m2 u4m2 4096 Oct 15 09:24 /home/u4m2
$ userdel -r u4m1; userdel -r u4m2
userdel: u4m1 mail spool (/var/mail/u4m1) not found
userdel: u4m2 mail spool (/var/mail/u4m2) not found
💡 要点:-K UMASK=077 时家目录仍是 750——HOME_MODE 存在时接管家目录权限,UMASK 只影响其余路径(如邮箱 spool);想让家目录 700 要用 -K HOME_MODE=0700。这与 3.10 注释第 155 行「HOME_MODE 未设置时才用 UMASK 推导」完全吻合。
四、实战示例
4.1 场景一:团队共享目录(umask 002 组可写协作)
协作组成员同属一个组、需要互改文件时,把掩码放宽到 002:
umask 002 && umask
umask -S
touch /root/demo/umask/shared.txt && mkdir /root/demo/umask/shareddir
stat -c '%a %n' /root/demo/umask/shared.txt /root/demo/umask/shareddir
实测回显:
$ umask 002 && umask
0002
$ umask -S
u=rwx,g=rwx,o=rx
$ touch /root/demo/umask/shared.txt && mkdir /root/demo/umask/shareddir
$ stat -c '%a %n' /root/demo/umask/shared.txt /root/demo/umask/shareddir
664 /root/demo/umask/shared.txt
775 /root/demo/umask/shareddir
要点:新文件 664(组可写)、新目录 775,配合「每用户私有组 + 共享属组」(chgrp 设共享组、目录加 setgid 位)就是标准的组协作模型;others 一栏仍无写权限,安全性不破防。
4.2 场景二:敏感数据落地(脚本内固化 umask 077)
处理密钥、备份、导出数据的脚本,开头固化 077,产物自动 600:
bash -c 'umask 077; echo secret > /root/demo/umask/secret.log; stat -c %a /root/demo/umask/secret.log'
umask
实测回显:
$ bash -c 'umask 077; echo secret > /root/demo/umask/secret.log; stat -c %a /root/demo/umask/secret.log'
600
$ umask
0022
要点:secret.log 直接落成 600,无需事后 chmod;脚本退出后父 shell 掩码纹丝不动(0022)——3.9 的作用域规则正好保证脚本内收紧不外溢。
4.3 场景三:建号配套(HOME_MODE 决定家目录权限)
给新账号配 700 私密家目录,用 useradd 的 -K HOME_MODE(实测见 3.11):
useradd -m -K HOME_MODE=0700 u4m2
ls -ld /home/u4m2
userdel -r u4m2
实测回显:
$ useradd -m -K HOME_MODE=0700 u4m2
$ ls -ld /home/u4m2
drwx------ 2 u4m2 u4m2 4096 Oct 15 09:24 /home/u4m2
$ userdel -r u4m2
userdel: u4m2 mail spool (/var/mail/u4m2) not found
要点:批量建号想要 700 家目录,改 /etc/login.defs 的 HOME_MODE 0750 → 0700 即全局生效;单次需求用 -K 覆盖。误把希望寄托在 -K UMASK=077 上是常见误区(3.11 实测它不改家目录)。
4.4 场景四:权限基线核查(umask 查新 + stat 抽查 + chmod 修补)
三件套组合处理存量不合规文件:
umask 0022
umask -S
stat -c '%a %n' /root/demo/umask/shared.txt
chmod 600 /root/demo/umask/shared.txt
stat -c '%a %n' /root/demo/umask/shared.txt
实测回显:
$ umask 0022
$ umask -S
u=rwx,g=rx,o=rx
$ stat -c '%a %n' /root/demo/umask/shared.txt
664 /root/demo/umask/shared.txt
$ chmod 600 /root/demo/umask/shared.txt
$ stat -c '%a %n' /root/demo/umask/shared.txt
600
要点:umask 只管「新生儿」(4.1 里 002 时落地的 shared.txt 是 664),存量文件必须 chmod;批量修补用 find 目录 -type f -perm /o+w -exec chmod o-w {} + 一类按位匹配,再配合收紧后的 umask 防复发。
五、注意事项与常见问题
Q1:umask 设了 077,为什么老文件权限没变? umask 只在文件创建瞬间参与运算(3.3 实测 f022.txt 始终 644),存量文件用 chmod 修补(4.4 实测 664→600)。要长期防复发,把收紧的 umask 写进相关用户的 shell 配置。
Q2:为什么新文件默认没有执行位?
创建起点是 0666(不含 x),掩码再怎么放宽也变不出执行位(3.4 计算),这是刻意的安全设计;需要执行权限时显式 chmod +x。目录起点是 0777,因为目录的 x 表示「进入」,默认需要。
Q3:setuid/setgid/sticky 这些特殊位受 umask 影响吗? 不受。umask 只作用于普通读写执行位(0777 范围),setuid/setgid/sticky 特殊位只能通过 chmod 显式设置或清除;这也意味着 umask 收紧不会意外破坏目录上的 setgid 协作位。另外 setuid 程序在执行期间创建文件同样会经过其进程的 umask,权限兜底不能依赖调用方 umask,敏感程序应在代码里显式 chmod。
Q4:为什么 root 是 0022,教程里普通用户是 0002?
来源在 /etc/login.defs:UMASK 022(第 151 行,pam_umask 默认)是基线,注释第 142 行说明 USERGROUPS_ENAB yes(每用户私有组)会调整普通用户的实际值——私有组模型下放宽组写(0002)不会泄露给他人,所以 Ubuntu 普通用户登录后常见 0002,root 会话保持 0022(本环境实测)。
Q5:退出终端再登录,umask 又变回默认了?
正常现象:umask 是进程属性,随 shell 生死(3.9 实测子 shell 退出即失效)。持久化位置:单用户 ~/.bashrc,全局 /etc/profile.d/umask.sh;登录会话基线则由 /etc/login.defs 的 UMASK 经 pam_umask 决定(3.10)。
Q6:umask 089 / umask abc 报错但没改值?
非法输入一律 rc=1 且掩码保持原值(3.8 实测失败不改值);089 超出八进制范围、abc 是非法符号模式(a 被当作 who、b 被当作运算符)。符号模式正确写法见 3.5:u=rwx,g=rx,o=rx。
Q7:umask -p 077 为什么没有任何输出?
-p 的回显行为只在省略 mode 时生效(umask -p → umask 0022);带 mode 时等价于静默设置(3.7 实测 rc=0 且掩码变为 0077)。运维脚本里设置后建议始终跟一句 umask 复核。
Q8:umask -K?为什么 useradd -K UMASK=077 家目录还是 750?
umask 是 shell 内置,没有 -K;-K 是 useradd 的参数。HOME_MODE 存在时优先决定家目录权限(3.11 实测对照),UMASK 只兜底其余创建路径——职责边界见 3.10。
Q9:脚本里怎么选择 umask 值? 经验基线:一般服务 0022;生成敏感文件(密钥/备份/导出)077;组协作目录 002 配合 setgid 位。写法统一四位八进制(0022),设置后回显复核(3.6/3.7 实测)。
六、参考链接
- umask(2) 系统调用手册(掩码与创建模式的与运算语义):https://man7.org/linux/man-pages/man2/umask.2.html
- bash 手册 Shell Builtin Commands(umask 内置命令权威说明):https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html
- chmod(1) 手册(符号模式与八进制模式语法):https://manpages.ubuntu.com/manpages/jammy/en/man1/chmod.1.html
- login.defs(5) 手册(UMASK/HOME_MODE/USERGROUPS_ENAB 等键):https://manpages.ubuntu.com/manpages/jammy/en/man5/login.defs.5.html
- bash(1) 手册(Ubuntu 22.04 jammy):https://manpages.ubuntu.com/manpages/jammy/en/man1/bash.1.html
- useradd(8) 手册(-K 覆盖 login.defs 与家目录权限):https://manpages.ubuntu.com/manpages/jammy/en/man8/useradd.8.html