FlowingDev

Chmod 终极解密:文件和文件夹的秘密握手礼

理解 Unix 文件权限,这个由读、写、执行权限构成的系统,保护着 Linux、macOS 和 Web 服务器上的文件和目录。

试用工具: Chmod计算器

一句话概括

chmod 是一个 Unix 命令,它定义了谁可以读取、写入或执行一个文件,是全世界绝大多数服务器和开发者机器上最基础的访问控制系统。

它解决了什么问题

想象一下计算的早期:一个人,一台机器,一次只做一个任务。在这样的系统上,文件权限简直是多此一举。如果整个电脑就你一个人用,你要保护文件不被谁看?你自己吗?

然后,在 20 世纪 60 年代末,Unix 在贝尔实验室诞生了。它的革命性思想是,从一开始就做一个多用户、多任务的操作系统。突然之间,多个程序员通过不同的终端登录到同一台大型机上,同时进行工作。这就带来了一个全新的、紧迫的问题:你怎么阻止丹尼斯不小心(或者“不小心”)删掉肯的新 C 语言编译器?你怎么让你的项目伙伴能读你的代码,但又不能修改它?你怎么保护核心操作系统文件不被一个笨手笨脚的实习生搞砸?

解决方案是一个设计得极其简洁而强大的所有权和权限系统,它被直接植入到文件系统本身。每个文件和目录都会有一个所有者,属于一个组,并为三类用户设定了一套特定的权限:所有者、组成员以及其他所有人。

那个用来“更改文件模式”(change the mode)——也就是修改这些权限——的命令,就被命名为 chmod。它成了系统管理员和用户用来声明“这个文件是我的,跟它打交道得按我的规矩来”的通用工具。它如此有效地解决了多用户混乱的问题,以至于同样的核心模型至今仍在地球上几乎每一台 Linux 服务器、macOS 电脑、安卓手机和物联网设备上使用。

底层工作原理

chmod 系统的核心是一个 3x3 的规则矩阵,外加几个特殊标记来增加点风味。要搞懂它,你需要理解三种权限类型以及它们可以应用到的三类用户。

三种权限:读、写、执行

所有的一切都围绕着你可以对文件或目录执行的三种基本操作。它们用字母 r、w 和 x 来表示。

  • 读 (r): 能打开并查看文件内容。
  • 写 (w): 能修改、更改或删除文件内容。
  • 执行 (x): 能将文件作为程序或脚本来运行。

但这里是第一个“坑”:这些权限对于目录来说,意思略有不同。这是一个超级常见的混淆点。

权限 对文件的作用 对目录的作用
读 (r) 能看文件内容 能列出目录中的文件名 (ls)
写 (w) 能改文件内容 能在目录内创建、重命名或删除文件
执行 (x) 能运行文件 能进入该目录 (cd) 并访问其中的文件

仔细想想最后一点。如果一个目录对你没有执行权限,即使你能看到它的内容,你也无法 cd 进去!你得有 x 权限才能穿过目录的这扇“门”。

三类用户:所有者、组、其他

Unix 权限不是对所有人都一样的;它们被分配给特定类别的用户。

  • 所有者 (u): 拥有该文件的单个用户。通常是创建文件的人。所有者拥有最高控制权。
  • **组 (g)**: 每个文件都属于一个组。这允许所有者与特定的团队成员共享访问权限。例如,“阿波罗计划”的所有文件都可以属于 apollo-devs` 组。
  • 其他 (o): буквально是其他所有人。系统上任何既不是所有者,也不属于该文件所属组的用户。

当你看到像 rwxr-xr-- 这样的权限字符串时,它实际上是为所有者、组和其他人(按此顺序)准备的三组 rwx 权限的组合。

  • rwx: 所有者可以读、写和执行。
  • r-x: 组可以读和执行,但不能写。
  • r--: 其他人只能读。

两种表示法:符号 vs. 八进制

有两种方式可以告诉 chmod 你想要什么,而开发者们永远都在这两种方式之间来回转换。

1. 符号表示法(“友好”模式) 符号表示法使用我们已经学过的字母(r, w, x 和 u, g, o, a,其中 a 代表“所有”)。你可以用 + 添加权限,- 移除权限,以及 = 来精确设置权限。

# 给予所有者执行权限
$ chmod u+x my_script.sh

# 移除组和其他人的写权限
$ chmod go-w sensitive_data.txt

# 精确设置权限:所有者可读写,组可读,其他人无任何权限
$ chmod u=rw,g=r,o= config.yml

这种方式非常适合进行小范围、有针对性的修改。

2. 八进制表示法(“极客”模式) 八进制更快,在脚本中更常见,而且它基于二进制。每个权限(r, w, x)都是一个 3 位数字中的一个比特位。

  • r (读) 是第一位,值为 4。
  • w (写) 是第二位,值为 2。
  • x (执行) 是第三位,值为 1。

你把想要的权限对应的数字加起来。

数字 二进制 (rwx) 授予的权限
0 000 (---) 无
1 001 (--x) 执行
2 010 (-w-) 写
3 011 (-wx) 写和执行
4 100 (r--) 读
5 101 (r-x) 读和执行
6 110 (rw-) 读和写
7 111 (rwx) 读、写、执行

一个像 755 这样的三位八进制代码代表了所有者、组和其他人的权限。

chmod 755 my_script.sh 的意思是:

  • 所有者: 7 (rwx) - 读、写和执行。
  • 组: 5 (r-x) - 读和执行。
  • 其他人: 5 (r-x) - 读和执行。

这对于那些可以安全地让其他人运行的可执行脚本来说,是一个非常常见的权限。而对于普通文件,一个常见的权限是 644(所有者可读写,其他人只能读)。

特邀嘉宾:SUID、SGID 和粘滞位

除了基本的 rwx 之外,还有三种特殊模式,由开头的第四个八进制数字表示(例如 chmod 4755)。

  • SUID (Set User ID) - 八进制 4: 当一个带有此位的可执行文件运行时,它会以文件所有者的权限执行,而不是以运行它的用户的权限。经典的例子是 passwd 命令,它需要修改受保护的 /etc/shadow 文件。passwd 可执行文件的所有者是 root,并且设置了 SUID 位,所以当一个普通用户运行它时,它会为了那一次操作临时获得 root 权限。这很强大,但也很危险。
  • SGID (Set Group ID) - 八进制 2: 与 SUID 类似,但可执行文件会以文件的组身份运行。更有用的是,当它设置在目录上时,在该目录内创建的任何新文件或目录都会自动继承父目录的组,而不是创建用户的首要组。这对于共享项目文件夹至关重要。
  • 粘滞位 (Sticky Bit) - 八进制 1: 这东西有段古怪的历史,但今天它几乎只用于目录。当一个目录设置了粘滞位(比如系统的 /tmp 文件夹),所有用户都可以在里面创建文件,但一个用户只能删除或重命名他们自己拥有的文件。它防止人们在共享空间里互相捣乱。

真实世界的案例

无法运行的脚本

一个初级开发者亚历克斯写了一个很棒的 shell 脚本来自动化服务器部署。他把 deploy.sh 提交到了 Git。在生产服务器上,他克隆了仓库,输入 ./deploy.sh,然后敲下回车。得到的响应是:bash: ./deploy.sh: Permission denied。他慌了。难道他把服务器搞坏了?一位资深开发者冷静地输入 ls -l deploy.sh,然后给他看输出结果:-rw-r--r--。文件有读写权限,但没有执行权限 (x)。Git 默认不保留执行权限。一个快速的 chmod +x deploy.sh 之后,脚本完美运行。 教训: 文件,特别是来自 Git 或 zip 压缩包等源头的文件,默认是不可执行的。你必须明确授予它们运行的权限。

共享项目文件夹噩梦

一个设计团队和一个开发团队需要在 Linux 服务器上的 /data/project-x 文件夹中共享资源。系统管理员把所有人都放进了 project-x-team 组,并给了这个组对该文件夹的写权限。但混乱随之而来。当一个设计师上传文件时,文件的所有者是 designer:designers,开发人员无法修改它。当一个开发人员创建一个子文件夹时,它的所有者是 dev:developers,设计师又无法向其中添加文件。每个人都在不停地请求系统管理员修复权限。解决方案?管理员运行了 chmod g+s /data/project-x。这给目录设置了 SGID 位。从那时起,在 /data/project-x 内创建的每个新文件和文件夹都会自动继承 project-x-team 组。天下太平了。 教训: 在目录上设置 SGID 是管理共享组文件夹的正确、不耍小聪明的办法。

公共网站的安全漏洞

一个自由职业的 Web 开发者为一个客户上线了一个简单的 PHP 网站。为了方便,他把数据库配置文件 config.inc.php 留在了和主页相同的目录里。这个文件以明文形式包含了数据库的用户名和密码。它的权限是默认的 644 (-rw-r--r--),这意味着 Web 服务器的用户可以读取它(这没问题),但地球上任何猜到 URL 的人也能读取它。一个安全扫描器发现了这个文件,攻击者下载了数据库凭据。正确的修复方法应该是 chmod 600 config.inc.php,让它只对所有者(即 Web 服务器进程)可读。 教训: 永远不要假设默认权限是安全的。像配置文件和私钥这样的敏感文件,应该尽可能地被锁定,权限设置得越严格越好。

常见错误和陷阱

  • chmod 777 这把大锤。 当感到沮丧时,很多人都想在一个目录上运行 chmod -R 777 .。这会递归地给予每个人对所有东西的读、写和执行权限。这是一个灾难性的安全漏洞,相当于数字世界里的“拆掉自家大门,还在草坪上立个牌子写着‘东西随便拿’”。别这么干。
  • 忘记目录的 x 权限。 你可能对一个文件有 r 权限,但却无法访问它,因为你对它路径中的某个父目录没有 x 权限。你需要对你想遍历的所有目录都拥有执行权限。
  • umask 的谜团。 有没有想过为什么你创建的新文件权限是 644 而不是 777?这是你的 umask 在起作用。umask 是你的 shell 应用的一个“掩码”,它在文件和目录被创建时移除某些权限。一个常见的 umask 值 022 会移除组和其他人的“写”权限,把默认的 666 变成 644。
  • 以为 chmod +x 和 chmod 755 一样。 它们不一样。chmod 755 my_file 是绝对地设置权限。chmod +x my_file 则是为那些已经拥有读权限的用户类别(所有者、组、其他)添加执行位,而不改变任何其他位。符号模式是相对的;八进制模式是绝对的。

为什么它值得你关注

如果你会接触到非 Windows 的命令行,你就需要理解 chmod。这不是可选项。这些知识在以下情况中至关重要:

  • 将任何应用程序部署到 Linux 服务器。
  • 编写需要被执行的脚本(Shell、Python、Node.js)。
  • 使用 Git,因为它对文件权限有自己的看法。
  • 设置文件共享或协作环境。
  • 通过限制对敏感文件的访问来加固服务器的安全性。
  • 使用 Docker,其中容器内部的文件权限至关重要。

chmod 是区分一个普通用户和一个真正的系统操作员或开发者的最初也是最基本的命令之一。理解它,是从仅仅使用机器到真正控制机器的成年礼。

深入探索

理论搞定,动手试试吧——100% 在你的浏览器中运行。

试用工具: Chmod计算器