第 5 章 · 05 默认权限:`umask`


文档摘要

第 5 章 · 05 默认权限: 本节摘要:前四节你学会了「读权限、改权限、定身份」。但有一个看似简单却少人深究的问题:当你 时,它的权限是怎么来的?为什么是 而不是 ? 答案在 这个「权限掩码」里。新建文件的权限 = 「全权限」减去 : 对应文件 、目录 。本节要把这套「反向计算」讲透——为什么用「掩码」(减法)而不是「直接给默认值」(加法)?因为安全默认原则:Linux 希望「默认情况下不给其他用户写权限」,用掩码能保证即使程序想给满权限,系统也会替你拦一道。理解 ,你才能在脚本里精确控制产物文件的权限。 内容来源:原项目「Linux 命令大全」 ,精选并套用体系化模板。 学习目标 阅读完本节,你应当能够: 说清 的作用:它是「权限掩码」,新建文件/目录的权限 = 全权限减去 。

第 5 章 · 05 默认权限:umask

本节摘要:前四节你学会了「读权限、改权限、定身份」。但有一个看似简单却少人深究的问题:当你 touch new.txt 时,它的权限是怎么来的?为什么是 644 而不是 777? 答案在 umask 这个「权限掩码」里。新建文件的权限 = 「全权限」减去 umask:umask 022 对应文件 644、目录 755。本节要把这套「反向计算」讲透——为什么用「掩码」(减法)而不是「直接给默认值」(加法)?因为安全默认原则:Linux 希望「默认情况下不给其他用户写权限」,用掩码能保证即使程序想给满权限,系统也会替你拦一道。理解 umask,你才能在脚本里精确控制产物文件的权限。

内容来源:原项目「Linux 命令大全」command/umask.md,精选并套用体系化模板。

学习目标

阅读完本节,你应当能够:

  1. 说清 umask 的作用:它是「权限掩码」,新建文件/目录的权限 = 全权限减去 umask
  2. 手算 umask 022 对应的新文件权限(644)和新目录权限(755)。
  3. 解释为什么文件的全权限是 666 而不是 777(出于安全,默认不给执行位)。
  4. umask 命令查看当前掩码(umask)和临时修改掩码(umask 077)。
  5. 理解「掩码」设计的安全动机:默认保守、需要时显式放开。

一、设计动机:为什么用「掩码」而不是「直接给值」

设想两种设计思路:

  • 设计 A(直接给值):系统有一个变量 default_perm,新建文件就赋这个权限。比如设成 default_perm=644,新文件就是 644
  • 设计 B(掩码):系统有一个变量 umask,新建文件权限 = 全权限减去 umask。比如 umask=022,新文件 = 666 - 022 = 644

表面看结果一样,但**「掩码」设计有一个微妙的安全优势**:程序在创建文件时可以指定「我希望这个文件权限是 X」(比如 open("f", 0666)),而 umask 会在程序指定的基础上再砍掉一层。这意味着:

  • 即使某个偷懒的程序 open("f", 0666) 想给所有人写权限,只要系统 umask022,实际创建出来的文件就是 644,其他用户拿不到 w
  • umask 是「系统级兜底」,不管程序怎么写,默认都保守。

关键概念:umask 是「权限的反向过滤器」——它不是「给多少权限」,而是「默认拦掉多少权限」。这种「从满权限开始减」的设计,保证了「默认安全」:宁可权限不够让用户手动加,也不能默认就给太多。

新文件和新目录的「全权限」不同

在算 umask 之前,先明确「全权限」是多少:

  • 目录的全权限是 777(rwxrwxrwx):目录天然需要 x 才能进入,所以全权限包含 x
  • 普通文件的全权限是 666(rw-rw-rw-):文件默认不给执行位——执行位是危险的(能跑代码),需要时必须显式 chmod +x,不能默认给。

💡 技巧:为什么文件默认不带 x?因为「可执行」是一个明确的「使用意图」,你应该主动声明「这是个脚本/程序」,而不是系统替你猜。这就是为什么你写个 script.sh 后必须 chmod +x 才能跑——umask 也拦了一道(哪怕 umask=000,新文件最多也是 666,不会有 x)。

计算公式

新文件权限 = 666 & ~umask (按位与 + 按位取反) 新目录权限 = 777 & ~umask

实务上用「减法」近似理解即可(下文解释为什么是「近似」):

新文件权限 = 666 - umask (大多数 umask 数值下成立) 新目录权限 = 777 - umask

二、高频组合与实战

1. 查看当前 umask

$ umask 022 $ umask -S # 符号式显示: u=rwx,g=rx,o=rx u=rwx,g=rx,o=rx

umask 不带参数,显示当前掩码(通常是 022002)。-S 给出符号式,更直观。

2. 计算最常见的 umask 022

$ umask 022 $ touch new.txt $ ls -l new.txt -rw-r--r-- ... new.txt # 644 $ mkdir newdir $ ls -ld newdir drwxr-xr-x ... newdir # 755

手算过程:

  • 文件:666 - 022 = 644(rw-r--r--)
  • 目录:777 - 022 = 755(rwxr-xr-x)

这是大多数 Linux 发行版的默认 umask。它意味着:新建文件对其他人只读,新建目录对其他人可进可读不可改——典型的「保守默认」。

3. 临时收紧 umask(创建敏感文件)

$ umask 077 # 只允许自己访问 $ touch secret.txt $ ls -l secret.txt -rw------- ... secret.txt # 600: 只有属主能读写 $ umask 022 # 改回默认(只影响当前 shell 会话)

umask 077 是处理敏感数据时的常用设置——新建的文件就只有自己能访问,不需要再手动 chmod 600这种「临时改 umask → 创建文件 → 改回 umask」是脚本里保护敏感产物的标准模式

4. 在脚本里临时改 umask

#!/bin/bash old_umask=$(umask) # 保存原 umask umask 077 # 收紧 echo "password" > /tmp/cred.txt # 创建的文件自动是 600 umask $old_umask # 恢复

这在脚本里创建临时密钥、凭证文件时极其有用——不依赖手动 chmod,创建瞬间就安全

5. 单用户系统用 umask 002

多用户系统用 022(防止其他用户乱动),单用户系统(如个人电脑)常用 002——让「同组用户」可写,便于同组协作:

$ umask 002 $ touch shared.txt $ ls -l shared.txt -rw-rw-r-- ... shared.txt # 664: 属主和属组都能写

002 适合「同一项目组、互相信任」的场景;022 适合「默认不信任其他用户」的服务器场景。

6. 不同场景的 umask 选择对照

把常见的 umask 值整理成对照表,方便选择:

umask 新文件 新目录 适用场景
022 644 755 服务器默认,其他人只读
002 664 775 单机/团队协作,同组可写
077 600 700 处理敏感数据,其他人完全无权
007 660 770 同组完全共享,其他人无权
000 666 777 不推荐,所有人可写(仅极特殊场景)

💡 技巧:生产环境脚本处理凭证、密钥时,临时切到 077——创建的文件自动是 600,无需额外 chmod,也不怕忘记。这是「安全默认」思维的应用。

7. 验证 umask 效果的实验

理解 umask 最好的方式是动手实验,观察不同 umask 下创建文件的差异:

$ umask # 看当前 022 $ touch a.txt; ls -l a.txt # 644 -rw-r--r-- a.txt $ umask 077 $ touch b.txt; ls -l b.txt # 600 -rw------- b.txt $ umask 000 $ touch c.txt; ls -l c.txt # 666 (注意: 不是 777, 文件默认无 x) -rw-rw-rw- c.txt $ mkdir d; ls -ld d # 777 (目录默认有 x) drwxrwxrwx d

注意 umask 000 时文件是 666 而不是 777——这验证了「文件全权限是 666」的设计。即使你把 umask 全开,新建的普通文件也不会有执行位,必须显式 chmod +x。这是 Linux 的双层安全保护:umask 拦一道 + 文件类型限制拦一道。

8. 把 umask 写进服务启动脚本

web 服务、数据库等服务创建的文件权限,受服务启动时的 umask 影响:

# systemd 服务可以在 unit 文件里指定 umask [Service] UMask=007 # 该服务创建的文件属组可读写, 其他无权 ExecStart=/usr/bin/myservice
# 传统 init 脚本在开头设 umask 027 # 属组只读, 其他无权

这是运维调权限的高级手段——不靠事后 chmod,而是从源头控制服务创建文件的权限。理解 umask 才能读懂这些配置。

三、踩坑与排错

坑 1:把 umask 算成「加法」或「直接当权限」

$ umask 022 # 新手误以为: umask 022 = 新文件权限是 022(??) # 实际: 新文件权限 = 666 - 022 = 644

umask 是「拦掉的权限」,不是「给的权限」。umask 022 意思是「拦掉其他的 w」(022 中第一个 0 是属主位,第二个 2 是属组位——等等,这里有个易错点,见下)。

实际上 022 三位分别对应 u/g/o:

  • 0(属主):拦掉 0,即属主全权(rwxrw)
  • 2(属组):拦掉 2(w),即属组 r-xr--
  • 2(其他):拦掉 2(w),即其他 r-xr--

⚠️ 注意:umask 的每一位是「要拦掉的权限和」:0=不拦、1=拦 x2=拦 w3=拦 wx4=拦 r5=拦 rx6=拦 rw7=全拦。所以 umask 077 = 属主不拦,属组和其他全拦,结果是文件 600、目录 700

坑 2:用减法算 umask 时遇到「借位」错觉

严格说,「全权限减 umask」不是十进制减法,而是按位运算(& ~umask)。差别出现在 umask 里有奇数位时:

$ umask 003 # 拦掉其他的 wx $ touch f.txt # 减法直觉: 666 - 003 = 663? 错! # 实际: 666 & ~003 = rw-rw-r-- (644)

为什么不是 663?因为 3 = 011(拦 wx),但文件的全权限 666 里其他位本来就只有 rw-,没有 x 可拦。所以拦掉 wx 实际只拦掉了 w,结果是 rw-rw-r--(644)。「减法」在 umask 含奇数位(1/3/5/7)时会误导,严格要用按位与。但日常 umask 多是偶数(022/002/077),减法够用。

坑 3:改了 umask 不生效

$ umask 077 $ touch a.txt $ ls -l a.txt -rw-r--r-- ... # 怎么不是 600?

如果改了 umask 还不生效,检查:

  1. 是不是在同一个 shell 里改的(子 shell 改了不影响父 shell)?
  2. 是不是有 alias touch 或函数拦截?
  3. 程序是不是显式指定了权限(如 install -m 644)覆盖了 umask?

坑 4:umask 设置不持久

$ umask 077 # 当前 shell 改了 $ exit # 退出 $ umask # 重开 shell, 又变回 022 022

umask 只对当前 shell(及其子进程)有效。要持久化,写进 ~/.bashrc~/.profile:

echo 'umask 077' >> ~/.bashrc

/etc/profile/etc/bash.bashrc 会影响所有用户,生产环境要慎重。

坑 5:目录的 x 被忽略导致权限算错

umask 022 → 目录 755 (有 x) umask 022 → 文件 644 (无 x)

记住文件和目录的全权限不同(目录 777、文件 666),所以同一个 umask 算出的结果不同。别把「文件的 644」错当成「目录的 644」(目录 644 是残废的,缺 x 进不去)。

本节要点回顾

  1. umask 是「权限掩码」:新建文件/目录权限 = 全权限减去 umask。掩码拦的是权限,不是给权限
  2. 全权限不同:目录 777(含 x)、文件 666(默认不给 x,出于安全)。
  3. umask 022 是最常见的默认:文件 666-022=644、目录 777-022=755
  4. umask 三位对应 u/g/o,每位是要拦掉的权限和:0=不拦、2=拦 w7=全拦。077 = 属组和其他全拦。
  5. 严格运算是按位与 & ~umask,但日常偶数 umask 用减法近似即可;奇数 umask 要小心借位错觉。
  6. 掩码设计的安全动机:系统级兜底,默认保守,需要时显式放开——即使程序想给满权限,umask 也会替你拦一道。
  7. 临时改 umask 是脚本保护敏感产物的标准模式:umask 077 → 创建文件 → 恢复;持久化要写 ~/.bashrc

权限部分到此结束。下一节我们把视角抬到磁盘:df 看每个分区的总容量与使用率,du 看某目录下各项的占用。两者看似都在「看磁盘」,实则维度完全不同——一个是分区级,一个是目录级。还要破解一个经典谜题:「为什么我删了个 10G 大文件,磁盘空间没释放?」答案藏在进程持有的文件描述符里。


发布者: 作者: 灏天文库 转发
评论区 (0)
U