一、引言:Linux 为什么要控制默认权限?
在前两篇中,我们学习了 Linux 的文件属性、基本权限,以及如何使用chmod、chown和chgrp修改权限。
但还有两个问题值得继续思考:
- 使用
touch创建一个文件时,我们没有指定权限,为什么文件仍然会自动获得一组权限? - 在一个允许所有用户写入的公共目录中,为什么用户可以创建自己的文件,却不应该随意删除其他用户的文件?
第一个问题涉及umask:新建文件和目录的默认权限如何产生。
第二个问题涉及Sticky Bit(粘滞位):如何在允许共享的同时限制删除行为。
这两个知识点看似独立,实际上体现了 Linux 权限设计的两个目标:
- 创建资源时,默认权限不能过度开放。
- 共享资源时,不能只考虑协作便利,还要考虑资源保护。
二、umask:新建文件的权限是怎么来的?
2.1 先观察一个现象
在 Ubuntu 终端中执行:
umask假设输出:
0002这表示当前 Shell 的文件创建权限掩码为0002。
接下来创建一个文件和一个目录:
touchtest.txtmkdirtest_dirls-ltest.txtls-ldtest_dir在没有其他权限机制干预的常见情况下,可以观察到:
-rw-rw-r-- test.txt drwxrwxr-x test_dir对应的权限数字分别是:
test.txt -> 664 test_dir -> 775问题来了:我们没有执行chmod,为什么它们会得到这些权限?
原因是,创建文件和目录时,程序会向操作系统提出创建请求,并提供一个期望的初始权限模式。内核再结合当前进程的umask等权限规则,确定新对象的权限。
因此,umask不是事后修改权限的命令,而是影响新建文件和目录默认权限的掩码。
2.2 先回顾 rwx 的数字表示
Linux 使用三位二进制位表示一组基本权限:
| 权限 | 二进制 | 八进制数值 |
|---|---|---|
r | 100 | 4 |
w | 010 | 2 |
x | 001 | 1 |
每个文件通常分别设置拥有者、所属组和其他用户的权限。
例如:
-rw-rw-r--拆分为:
rw- rw- r-- 用户 用户组 其他用户对应:
664其中:
- 用户拥有读、写权限:
4 + 2 = 6 - 用户组拥有读、写权限:
4 + 2 = 6 - 其他用户只有读权限:
4
理解了这个基础,才能继续理解umask为什么能够屏蔽权限。
2.3 文件和目录的起始权限为什么不同?
在常见的 Linux 文件创建机制中,用于计算默认权限的基础模式通常是:
| 对象类型 | 基础模式 | 含义 |
|---|---|---|
| 普通文件 | 666 | rw-rw-rw- |
| 目录 | 777 | rwxrwxrwx |
这里的基础模式不是说最终创建出来的文件一定具有这些权限,而是计算时使用的基础值。
为什么普通文件的基础模式不是777?
因为普通文件默认不应自动获得执行权限。一个刚刚创建的文本文件通常只是数据,不应该仅仅因为它被创建出来,就默认成为可执行文件。
目录则不同:目录的x权限与进入、搜索目录有关,因此目录的基础模式通常包含执行权限。
注意:程序可以请求不同的创建模式,文件系统也可能受到 ACL 等机制影响。因此,这里的666和777是理解常见默认权限计算的基础模式,不代表所有创建操作都必然采用它们。
三、umask 的核心:不是减法,而是位运算
3.1 umask 究竟屏蔽了什么?
可以先记住一句话:
umask中对应权限位为1的位置,表示该权限位不应出现在最终权限中。
例如:
umask = 0002最后一位的八进制数字2,对应二进制:
010它代表屏蔽其他用户权限组中的写权限位。
于是,新建文件时,基础模式中的其他用户写权限就会被屏蔽。
这也解释了为什么umask 0002通常会让新建文件的权限从666变为664。
3.2 为什么公式是 mode & ~umask?
常见的权限计算表达式为:
final_mode=requested_mode&~umask;这里涉及两个位运算符:
~:按位取反。&:按位与。
先看按位与的规则:
| A | B | A & B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
按位与的核心特点是:只有两边都为1,结果才是1。
因此,如果我们希望某个权限位被保留,就需要让基础模式和掩码取反后的对应位都为1。
如果掩码中的某个权限位是1,取反之后就会变成0。基础模式与这个0进行按位与,结果只能是0,对应权限便被屏蔽了。
这就是umask的底层逻辑。
3.3 手动推导:umask 0002
先看新建目录。
基础模式:
777 = 111 111 111掩码:
002 = 000 000 010取反后,只保留我们需要讨论的低九个权限位:
~002 = 111 111 101执行按位与:
111 111 111 777:目录基础模式 & 111 111 101 ~002:屏蔽写权限位 ------------- 111 111 101 775:最终权限因此:
777 & ~002 = 775再看普通文件。
110 110 110 666:文件基础模式 & 111 111 101 ~002 ------------- 110 110 100 664:最终权限因此:
666 & ~002 = 664这里的二进制演算只展示权限所使用的九个基本权限位。实际计算机中的按位取反还会涉及更高位,所以不能把无限位宽的~002直接理解为一个只有九位的数;我们展示的是权限位范围内的结果。
3.4 为什么不能直接做减法?
看到:
666 - 002 = 664 777 - 002 = 775你可能会觉得,直接相减不就行了吗?
但这只是部分例子中碰巧得到相同结果,不能作为通用算法。
原因在于:umask表示的是需要屏蔽哪些权限位,而不是需要从权限数字中减去多少。
例如:
基础模式:666 umask: 022正确结果:
666 & ~022 = 644如果用普通减法:
666 - 022 = 644这次结果相同。
但再看:
基础模式:666 umask: 003按照位屏蔽规则:
003表示屏蔽其他用户组的写权限和执行权限对应的位。- 普通文件基础模式
666本身没有执行权限,因此屏蔽执行权限不会产生额外变化。 - 屏蔽其他用户的写权限后,最终权限为
664。
而直接做八进制减法:
666 - 003 = 663得到的结果反而让其他用户失去了读权限,并没有正确表达“屏蔽写和执行权限”的含义。
结论:权限掩码操作的是二进制权限位,因此必须按照位运算规则理解,不能将其等同于数字减法。
四、在 Ubuntu 中验证 umask
4.1 查看当前掩码
umask如果想看到符号形式,可以执行:
umask-S输出形式可能类似:
u=rwx,g=rwx,o=rx具体输出以当前 Shell 环境为准。
4.2 临时修改掩码
可以在当前终端中执行:
umask0002然后创建测试对象:
touchumask_filemkdirumask_dirls-lumask_filels-ldumask_dir在常见默认创建模式下,预期分别为:
-rw-rw-r-- umask_file drwxrwxr-x umask_dir对应:
664 775如果你想验证不同掩码的效果,可以尝试:
umask0022touchfile_0022mkdirdir_0022ls-lfile_0022ls-lddir_0022常见结果:
file_0022 -> 644 dir_0022 -> 755再尝试:
umask0077touchprivate_filemkdirprivate_dirls-lprivate_filels-ldprivate_dir常见结果:
private_file -> 600 private_dir -> 700这时新建文件只有拥有者能够读写,新建目录只有拥有者具有完整的基本权限。
4.3 umask 修改后会永久生效吗?
通常不会。
直接执行:
umask0077会修改当前 Shell 的掩码,当前 Shell 创建的子进程通常也会继承相应的掩码状态。退出该 Shell 后,重新登录时的掩码可能由启动配置重新设置。
如果确实需要长期修改,可以根据自己的 Shell 环境,在对应的用户启动配置文件中设置。但在学习阶段,建议先在当前终端实验,不要随意修改全局配置。
特别注意:不要在不理解影响范围的情况下,把严格或过于宽松的umask设置写进系统级配置。
五、从默认权限转向共享目录:出现了什么矛盾?
理解umask后,我们再看第二个问题。
假设一台 Linux 服务器上有多个普通用户,他们都需要在一个公共目录中创建临时文件。
如果公共目录不允许其他用户写入,那么协作就会受限。
但如果为了方便协作,直接允许所有用户读、写、进入这个目录,又会带来新的问题:
用户可能删除自己并不拥有的文件。
这里有一个很容易误解的知识点:
删除目录中的文件,通常主要检查的是父目录的权限,而不是被删除文件本身的写权限。
5.1 为什么删除文件看的是目录权限?
例如,目录结构如下:
/shared/ └── alice.txt假设:
/shared允许某个用户写入并搜索。alice.txt属于 Alice。- 该用户不是 Alice,也不是 root。
即使alice.txt本身没有授予该用户写权限,如果该用户对父目录具有足够的权限,且没有其他限制,仍然可能删除这个目录项。
为什么?
从文件系统的角度看,删除文件并不等同于打开文件并修改内容。删除操作需要修改的是父目录中的目录项,也就是让目录不再记录这个文件名与对应对象之间的关联。
因此:
- 修改文件内容,主要检查文件自身的写权限。
- 删除或重命名目录中的条目,主要检查父目录的写权限和搜索权限。
这就是为什么“文件不可写”并不一定意味着“文件不可删除”。
5.2 用流程图理解删除权限
这个流程是帮助理解的简化模型。实际操作还可能受到 ACL、只读挂载、文件系统属性等因素影响。
现在,问题就明确了:
我们希望用户可以在公共目录中创建自己的文件,但不能随意删除别人的文件。
这正是粘滞位要解决的核心问题。
六、Sticky Bit:让公共目录既能共享,又能保护文件
6.1 什么是粘滞位?
Sticky Bit,中文通常称为“粘滞位”,是一种特殊权限位。
在现代 Linux 中,它最常见的用途是保护设置了该权限的共享目录。
当目录设置了粘滞位后,即使用户对目录拥有写权限,也不能因此随意删除或重命名其他用户的文件。
在典型的目录场景中,允许删除目录项的身份包括:
- 文件的拥有者。
- 目录的拥有者。
- 超级用户 root。
当然,操作仍然需要满足其他适用的权限与系统规则。
6.2 粘滞位在权限字符串中如何显示?
观察一个常见的权限字符串:
drwxrwxrwt最后的t就是粘滞位的标志。
普通目录权限的最后一位通常对应其他用户的执行权限;设置粘滞位后:
- 如果其他用户执行权限也存在,通常显示为小写
t。 - 如果其他用户执行权限不存在,则通常显示为大写
T。
例如:
drwxrwxrwt drwxrwxrwT这两个字符串都体现了粘滞位,但对应的执行权限情况不同。
6.3 为什么/tmp通常有粘滞位?
Linux 系统中的/tmp通常用于存放临时文件。
多个程序、多个用户可能同时使用这个目录,因此它需要允许不同用户创建临时文件。
可以查看:
ls-ld/tmp常见输出类似:
drwxrwxrwt ... /tmp重点看末尾的t。
/tmp通常具有:
- 所有者的完整权限。
- 所属组和其他用户的读、写、执行权限。
- 粘滞位。
这意味着普通用户可以在其中创建临时文件,但不能仅仅因为目录可写,就随意删除其他用户拥有的文件。
因此,/tmp展示了一种典型的权限设计思路:
允许共享目录本身,同时对目录项的删除和重命名增加身份限制。
七、如何设置粘滞位?
7.1 使用符号方式
假设我们创建一个用于实验的目录:
mkdirsticky_demochmod777sticky_demols-ldsticky_demo此时,权限通常类似:
drwxrwxrwx ... sticky_demo设置粘滞位:
chmod+t sticky_demo再次查看:
ls-ldsticky_demo预期看到:
drwxrwxrwt ... sticky_demo最后的t表示粘滞位已设置。
这里使用的是自己创建的实验目录,不需要修改系统目录,也不需要执行危险的全局权限修改。
7.2 使用数字方式
Linux 也支持使用特殊权限位的数字表示。
粘滞位对应的数值为1,写在普通三位权限数字之前。
例如:
chmod1777sticky_demo其中:
1 777 │ └── 普通权限:rwxrwxrwx └──── 粘滞位执行后,目录的权限通常会显示为:
drwxrwxrwt需要注意,特殊权限位与普通的rwx权限位属于不同的概念,不要把1777理解成四组普通读写执行权限。
八、umask 和粘滞位有什么本质区别?
这两个知识点都与 Linux 权限有关,但它们解决的是不同阶段的问题。
| 对比项 | umask | Sticky Bit |
|---|---|---|
| 主要作用 | 控制新建对象的默认权限 | 限制共享目录中的删除、重命名行为 |
| 主要生效时机 | 创建文件或目录时 | 对设置了粘滞位的目录进行相关操作时 |
| 关注对象 | 新建对象的基本权限位 | 目录中的文件条目及相关用户身份 |
| 常见使用方式 | umask 0022 | chmod +t directory |
| 典型场景 | 避免新建文件默认过度开放 | 保护/tmp一类共享目录中的文件 |
可以这样理解:
umask关注的是:一个对象刚创建出来时,默认应该开放哪些权限?- 粘滞位关注的是:一个目录允许多人共同使用时,谁可以删除其中的文件?
一个控制创建阶段的默认权限,一个在共享目录场景中增加删除与重命名的限制。二者互不替代。
九、常见误区总结
误区一:umask 是从默认权限中直接减去一个数字
错误。
umask表示需要屏蔽的权限位。应从位运算角度理解:
最终权限 = 请求的基础权限 & ~umask误区二:新建文件一定是 666,新建目录一定是 777
不准确。
它们是常见计算场景中的基础模式。最终权限还取决于创建请求、umask以及可能存在的其他权限机制。
误区三:文件没有写权限,就一定不能删除
错误。
删除文件通常主要检查父目录的写权限和搜索权限;设置粘滞位后,还需要检查相关用户身份。
误区四:目录有粘滞位,就不能删除里面的文件
错误。
粘滞位并不是禁止所有删除操作,而是限制哪些用户可以删除或重命名目录中的条目。文件拥有者、目录拥有者和 root 通常仍然可以删除符合条件的文件。
误区五:只要设置了粘滞位,其他权限就不重要了
错误。
粘滞位不会代替目录的基本权限检查。用户仍然需要满足适用的访问条件,粘滞位是在相关权限检查之外增加的一层限制。
十、总结
本篇学习了 Linux 权限管理中的两个重要机制。
第一,umask通过屏蔽权限位影响新建文件和目录的默认权限。理解它的关键不是记住几个数字,而是理解按位取反与按位与的运算逻辑。
第二,Sticky Bit 用于解决共享目录中的权限矛盾。它允许用户在公共目录中协作,同时限制普通用户随意删除或重命名其他用户的文件。
回到最初的两个问题:
- 为什么新建文件会自动获得一组权限?因为创建请求的基础权限会受到
umask等规则的影响。 - 为什么公共目录可以允许多人写入,却又保护其他人的文件?因为粘滞位能够在共享目录中增加身份方面的限制。
Linux 权限管理并不是简单地给文件设置几个rwx标志,而是围绕资源访问、默认安全性和多用户协作建立起来的一套机制。
当我们能够从“为什么需要这条规则”出发,再推导它的行为,就不再只是记住命令,而是在理解操作系统的设计思想。