“Permission denied。”这大概是Linux新手最常撞见的一句英文。我见过太多人在第一次写脚本、第一次部署网站、第一次挂载磁盘时被它拦在半路,然后一脸茫然地在搜索引擎里敲下“Linux chmod 777”。如果你也处在这个阶段,这篇文件权限专题就是为你准备的。作为Linux文件权限机制最直接的体现,chmod、chown、umask这一组命令能帮你彻底搞懂“谁可以对这个文件做什么”,而搞懂之后,你几乎不会再被权限问题卡住超过五分钟。
下面我会从权限位的底层含义讲起,依次拆解chmod、chown、三个特殊权限位、umask,最后用一次真实的Permission denied排查过程,把这些命令串成一套完整的排错思路。内容不深,但每一段都是实际使用中踩过的点和用得上操作。
1. 权限位的本质:rwx 对文件和目录的含义完全不同
先别急着记命令,把权限想明白比命令重要。任何文件或目录,在Linux里都有一个权限描述,你执行ls -l就能看到。
-rw-r--r-- 1 alice devs 4096 Jan 10 10:32 notes.txt drwxr-xr-x 2 alice devs 4096 Jan 10 10:33 scripts这串字符从左往右看,第1位是类型,-代表普通文件,d代表目录,l代表符号链接。后面9位分成三段,每段三位,依次是文件属主(owner)、属组(group)、其他用户(other)的权限。三段对应关系一定要背下来:第一段是“你自己”,第二段是“和你在同一个组的人”,第三段是“全世界剩下的人”。
然后rwx三个字母,对文件和目录的解释完全不一样,这是新手栽跟头最多的地方。
对普通文件:
- r:可以读取文件内容,比如
cat、less - w:可以修改文件内容,比如 vim 保存、echo 重定向
- x:可以把文件当作程序执行
对目录:
- r:可以列出目录里有什么名字
- w:可以在目录里新建文件、删除文件、重命名文件
- x:可以进入目录(cd),以及访问目录内文件的具体信息
看到区别没有?目录的w权限,意味着“你能删除这个目录里的文件”——哪怕你不是那个文件的所有者。这是整个权限模型里最反直觉的一条。很多人以为“文件有w权限才能删除文件”,但实际上删除动作依赖的是文件所在目录的w权限。这一点在共享目录里天天发生。
目录的x权限同样重要。你可以在别人的目录上看到rw-,但没有x权限就进不去,ls -l也只能看到文件名,连文件大小都读不出来,因为读文件属性也依赖目录的x权限。一句话总结:x权限才是通往目录的“钥匙”,r和w只是进去之后能干些什么。我把文件与目录的rwx含义整理成了表格,方便对照。
| 权限 | 文件含义 | 目录含义 |
|---|---|---|
| r | 可读取文件内容 | 可列出目录内容(ls) |
| w | 可修改文件内容 | 可新建、删除、重命名目录内的文件 |
| x | 可执行该文件 | 可进入目录、可访问目录内文件属性(cd、stat) |
提示:判断权限问题的时候,先看清楚目标是文件还是目录。同一组字母,在文件和目录上完全是两个意思。
2. chmod 的两种改法:数字法为什么是主流
chmod 是修改权限的命令,全称 change mode。它有数字和符号两套写法,我更推荐两个都会,然后日常以数字法为主。
2.1 数字法:三个权重值拼出权限
数字法的逻辑很简单:r当作4,w当作2,x当作1。每段权限把三个数字相加,得到一个0到7的数字,三段加在一起就是chmod的参数。
rwx = 4+2+1 = 7 rw- = 4+2 = 6 r-x = 4+1 = 5 r-- = 4 = 4 --- = 0 = 0所以chmod 755 script.sh,意思就是:属主rwx(7),属组r-x(5),其他r-x(5)。这是脚本最常见的权限,属主能读写执行,其他人都能读和执行但不能改。
数字法的数学原理就这么简单,没必要死记硬背,理解一遍就能推出来。它为什么流行?因为一条命令能完整表达三段权限,写脚本的时候尤其方便,一串数字放进去不会写错。
2.2 符号法:临时微调更安全
符号法长这样:chmod u+x file、chmod g-w file、chmod o=r file。u是属主,g是属组,o是其他,a是所有角色;+加权限,-减权限,=直接指定为某个值。
我自己用符号法最多的场景是:只改一个角色、一个权限位,比如给刚写的脚本加执行权限:chmod +x run.sh。这里的+x省略了角色,默认就是a,给所有人都加执行权限。如果只打算给属主加,就要写成chmod u+x。
符号法的好处是“只动要动的那一位”,不会像数字法那样把其他位也重写一遍;坏处是表达完整权限多角色时太啰嗦。所以我的习惯是:大改用数字法,微调用符号法。
2.3 一组常用权限对照
把日常最常用的权限组合列在下面,可以直接当速查表用:
| 权限 | 数值 | 典型用途 |
|---|---|---|
| 644 | rw-r--r-- | 普通文件、配置文件、静态网页 |
| 755 | rwxr-xr-x | 脚本、可执行程序、普通目录 |
| 700 | rwx------ | 私有目录,只允许属主进入 |
| 600 | rw------- | 私密文件,如 SSH 私钥 |
| 640 | rw-r----- | 需要给属组读权限的配置文件 |
| 2770 | rwxrws--- | 团队共享目录(稍后会讲SGID) |
这里最想提醒的是:别动不动就chmod 777。777意味着所有人都能读写执行。你在自己测试机上图省事可能没事,一旦放到生产环境,任何能摸到这台机器的用户都能改你的文件、执行你的脚本。我在实际中见过不止一次,某个服务起不来,排查半天发现是部署的人图省事对整个目录chmod -R 777,后来还被隔壁用户改掉了配置文件。
2.4 递归修改时的隐藏坑
对目录用chmod -R的时候要小心:它会把目录下所有东西都套用同一个权限,包括普通文件。但文件的合理权限和目录的合理权限往往不是同一个值——比如文件通常不需要x权限,目录却需要x权限才能进入。
更稳的做法是分开处理:
find /data/shared -type d -exec chmod 755 {} \; find /data/shared -type f -exec chmod 644 {} \;先给目录755,再给文件644,这样目录可以进入,文件不会被多出执行权限。递归操作前先想清楚“目录和文件是否需要不同权限”,能省掉后面很多麻烦。
3. 属主属组怎么改:chown 与 chgrp 的高频误操作
chmod 管的是权限值,但“这个文件属于谁、属于哪个组”,由 chown 和 chgrp 决定。这两个命令在权限问题上镜率一样高,但坑也比想象中多。
3.1 基本语法
chown 改属主和属组,一条命令可以同时完成:
chown alice:devs report.pdf # 属主改成 alice,属组改成 devs chown alice report.pdf # 只改属主 chown :devs report.pdf # 只改属组,等价于 chgrp devs report.pdfchgrp 是专门改属组的命令,不过现代写法一般直接用chown :group一步到位。查看属主属组最简单的方式就是ls -l,第一列是属主,第二列是属组。更详细的看stat:
stat report.pdf # 会显示 Access (0644) 以及 Uid、Gid 的数值3.2 为什么普通用户不能随便 chown
有个设计你可能没意识到:chown 里,改属组可以由文件当前属主操作,但改属主基本只有 root 能操作。普通用户把自己文件 chown 给别人,在 Linux 里是不允许的。
原因是安全设计:如果能随便改属主,那我把系统里别人的文件先 chown 给我,再改权限,不是瞬间越权了吗?所以系统干脆把这条路堵死。想明白这个点,你在生产环境就不会反复尝试用普通用户改属主,而是直接sudo chown。
3.3 我踩过的两个坑
第一个坑是chown -R没看路径。某次我在一台服务器上想给某个应用目录统一改属主,手一快把命令末尾的目录名写成了应用目录的父目录。那条命令一执行,相当于把父目录以及下面大量系统文件的属主全改成了应用用户。结果是系统文件属主全部错乱,服务一个接一个起不来,最后只能靠备份恢复。从此以后,凡是-R的操作,我必先用ls或find确认目标范围,再动手。教训很简单:递归操作之前,先打印一遍将要影响的路径范围。
第二个坑是符号链接。chown 默认跟随符号链接,也就是说你 chown 一个软链接,实际改的是它指向的文件,不是软链接本身。要想改软链接自己的属主,得加-h参数。
chown -h alice link_file很多人不知道这个区别,查问题查半天。用ls -l看到是l开头的文件时,心里就要绷起这根弦。
3.4 一个典型场景:网站文件属主错乱
部署过网站的人都碰到过这种问题:程序以专用服务账户运行,上传文件后,文件属主变成了服务账户。这时候开发者自己用编辑器去改文件,没权限保存。办法不是把文件chmod 777,而是把开发者加进相关组的成员,并把文件属组改成那个组。比如:
sudo usermod -aG web alice sudo chown -R :web /var/www/site chmod -R g+rw /var/www/site这样开发者的个人账户 alice 在 web 组里,文件属组是 web,组权限可读写,就能正常编辑了。既不用给“其他用户”开权限,也比 777 安全得多。这是团队协作里最标准的做法。
4. 三个特殊权限位:SUID、SGID、Sticky Bit 的实际用途
普通 rwx 只是基础,Linux 还有三个特殊权限位。它们平时不显眼,但关键时刻作用巨大,也是实际排查里最容易迷惑人的东西。
4.1 SUID:以文件属主身份运行
SUID 全称是 Set User ID,配置后,在文件属主的执行权限位上显示为s。它的作用是:当普通用户执行这个程序时,临时以文件属主(通常是 root)的身份来运行。
最典型的例子是 passwd。普通用户要修改自己的密码,本质上要写 /etc/shadow,但这个文件只有 root 能读写。普通用户为什么改得动?因为 /usr/bin/passwd 这个程序带 SUID,执行时以 root 身份运行,帮你把密码写进了 shadow。你可以ls -l /usr/bin/passwd看一眼,属主执行权限位上就是rws。
设置和取消:
chmod u+s 程序文件 # 符号法 chmod 4755 程序文件 # 数字法,4开头 chmod u-s 程序文件 # 取消注意两点。第一,SUID 只对二进制可执行文件有意义,对 Shell 脚本无效。这是安全设计,否则一个带 SUID 的 .sh 脚本,等于给了普通用户一条随意提权的通道。第二,执行权限位上的显示:有 x 权限时显示小写s,没有 x 权限时显示大写S。大写 S 说明虽然设置了 SUID 位,但文件不能执行,这个位实际是“摆设”。看到大写 S 的时候要意识到:这个 SUID 并没有真正生效。
从安全角度多说一句:带 SUID 的 root 二进制是提权攻击的主要入口,运维上有一句老话,“一个 SUID 就是一个潜在后门”。所以上线前要扫描系统里所有带 SUID 的文件:
find / -perm -4000 -type f 2>/dev/null结果里出现不认识的程序,就要警惕。
4.2 SGID:目录协作的利器
SGID 是 Set Group ID。它用在二进制程序上时,程序以属组的身份运行;但真正日常用到的地方是目录。对一个目录设置 SGID 后,目录里新建的文件和子目录会自动继承这个目录的属组,而不是创建者自己的主组。
这个特性是团队共享目录的基石。想想看:一个团队三个人,想让 /data/shared 里所有文件大家都能改。如果各自用自己的主组创建文件,组权限根本对不上,互相没权限。但如果目录带 SGID,所有人都以同一个组身份创建文件,组内读写协作就不需要频繁改权限。
设置方法:
sudo groupadd team sudo usermod -aG team alice bob carol sudo mkdir /data/shared sudo chown root:team /data/shared sudo chmod 2770 /data/shared # 2开头设置SGID做完之后,alice、bob、carol 在里面随便创建文件,新文件的属组都是 team,大家互相能读写。这个组合(2770)在团队协作里极其常见,理解了再去用,比死记命令强得多。
4.3 Sticky Bit:共享目录里的“护身符”
Sticky Bit 在“其他用户”的执行权限位上显示为t。它解决的是共享目录里的删除权问题。
按目录权限规则,只要一个目录对你有 w 权限,你就能删除里面任何文件,哪怕文件是别人的。这在共享目录里是个灾难。但 Sticky Bit 可以改变规则:设置了它之后,只有文件所属者(或 root)才能删除或重命名文件。你仍然可以读别人的文件,但动不了别人的文件。
/tmp 目录就是最典型的例子。所有用户都能往 /tmp 里写文件,但你不能乱删别人的临时文件。ls -ld /tmp你会看到drwxrwxrwt,最后一位就是 t。
设置和取消:
chmod o+t /data/shared chmod 1777 /data/shared # 1开头设置 chmod o-t /data/shared同样注意大小写:有 x 权限显示小写t,没有 x 权限显示大写T,大写 T 也说明这个位没真正生效(虽然目录场景基本都有x)。
4.4 三个特殊权限位速查
| 特殊权限 | 数字 | 作用位置 | 核心作用 |
|---|---|---|---|
| SUID | 4000 | 属主x位 | 普通用户执行时以文件属主身份运行 |
| SGID | 2000 | 属组x位 | 目录内新建文件自动继承目录属组 |
| Sticky Bit | 1000 | 其他x位 | 目录内仅文件属主才能删除自己的文件 |
提示:设置多个特殊权限位时可以叠起来,比如 3777 就是 SGID + Sticky Bit + 普通权限的组合。但实践里一般建议一次只用一个特殊位,避免权限语义混乱。
5. umask:新文件的默认权限是怎么算出来的
你可能早就发现,在系统里随便touch一个新文件,权限默认是 644;mkdir一个新目录,默认是 755。为什么?不是内核凭空给的,而是 umask 决定的。
5.1 umask 的计算逻辑
umask 是一个权限掩码,表示“新建文件时要屏蔽掉哪些权限位”。每个用户都有自己的 umask 值,用umask命令直接看:
$ umask 0022计算规则:文件的基础权限是 666(rw-rw-rw-),目录的基础权限是 777(rwxrwxrwx),然后去掉 umask 中为 1 的位。注意这是按位去掉,不是简单的算术减法。举例:umask 022,就是把属组的写权限位和其他的写权限位都去掉。
umask 022 时:
- 新文件:666 去掉属组 w 和其他的 w,得到 644
- 新目录:777 去掉属组 w 和其他的 w,得到 755
为什么文件基础权限是 666 而不是 777?因为新建的普通文件默认就不应该带执行权限,执行权限要手动通过chmod +x或安装程序时明确给。而目录必须有 x 权限才能进入,所以目录基础权限是 777。
umask 常见值对比:
| umask | 新文件 | 新目录 | 适应场景 |
|---|---|---|---|
| 022 | 644 | 755 | 单机/默认环境,组权限保守 |
| 002 | 664 | 775 | 团队成员之间默认共享可写 |
| 027 | 640 | 750 | 组内只读,外部完全封闭 |
| 077 | 600 | 700 | 个人私有,不信任任何人 |
5.2 修改 umask
临时修改,直接在 Shell 里敲:
umask 007这只对当前 Shell 和它启动的子进程有效,关掉终端就恢复。想永久生效,写在~/.bashrc、/etc/profile或/etc/profile.d/下放一个脚本。系统级修改建议放在/etc/profile.d/下,这样所有用户登录都会读到。
一个常见的误区:umask 只影响新建的文件,对已经存在的文件没有任何作用。所以别指望改了 umask 能把之前的文件权限“修正”回来。
5.3 实测一次 umask 的影响
我在一台开发机上把 umask 改成 0000 测试过,然后 touch 了一个文件,权限立刻变成 666。这意味着目录里任何人都有写权限,当时我就明白了为什么共享目录规范里第一条就是“把 umask 设成 002 或 007”。生产环境里我见过因为某人的.bashrc把 umask 设成 000,导致一台机器上配置被别的用户顺手改掉的案例。所以查权限问题,除了看文件本身的权限,也看一眼创建它的用户 umask 是几。
6. 从 Permission denied 到定位:一条实用的权限排查链路
前面所有内容,最后都落到一个能力上:线上环境报错 Permission denied 时,怎么在五分钟内定位问题。我用自己的真实排查过程来讲。
6.1 一个典型的 403 案例
某开发者部署了一个静态站点,Nginx 进程由专用服务账户运行,站点目录 /var/www/site 下的文件权限肉眼看着一切正常:属主是 root,属组是 root,文件是 644。但访问站点永远 403。肉眼判断“文件权限没问题”,其实是排查里最容易被带偏的地方。
正确的第一步是确认进程身份:
ps aux | grep nginx看输出里用户名是哪个。第二步,看站点目录每一级的权限:
ls -ld / /var /var/www /var/www/site drwxr-xr-x 18 root root 4096 ... /var drwxr-xr-x 3 root root 4096 ... /var/www drwx------ 2 root root 4096 ... /var/www/site破案了。/var/www/site 是 700,属主是 root。服务账户访问这个目录,需要的是目录的 x 权限。700 意味着只有 root 能进,而服务账户不是 root,所以整条路径在这里被掐断。文件本身 644 完全没毛病,问题出在进入目录这一环。
修复思路两种:要么把站点目录属主改成服务账户,要么给其他用户加 x 权限。一般取前者:
sudo chown -R 服务账户:服务账户 /var/www/site6.2 父目录链式权限:最隐蔽的坑
上面案例对应的是一条极其隐蔽的坑:文件权限完全正常,但路径上的某个父目录没有 x 权限,导致整个路径不可达。
Linux 访问一个文件,是从根目录一级一级“穿越”下来的,路径上每一个目录都必须有 x 权限,否则后面的一切都被挡住。而且这种问题报错往往还是“Permission denied”,不会明确告诉你“是第几级目录挡的”。我在帮人排查时最常用的一条命令是namei,它能一次性把路径上每一级目录的权限打出来:
namei -l /var/www/site/index.html如果某一行末尾出现drwx------或类似的权限,那基本就是这一级目录的问题。这个命令在很多发行版默认就能用,没有的话可以用包管理器装一下。
6.3 权限排查的顺序清单
经过几次真实排障,我总结出一个固定顺序,可以参考:
- 先看进程身份,确认“谁在访问”:
ps aux | grep 服务名 - 再看目标文件属主和权限:
ls -l 目标文件 - 再检查路径上每一级父目录的 x 权限:
namei -l或逐级ls -ld - 检查有没有 SELinux 等强制访问控制干扰:看审计日志
- 最后考虑 ACL 覆盖:
getfacl看一眼是否有特殊 ACL 规则 - 如果以上都没问题,查看磁盘挂载选项,比如
noexec、ro之类
这六步走完,95% 的权限问题都能定位。真正走到第 5、6 步的情况很少,但一旦遇到,前面基础没打好的人会完全卡住。ACL 在本文里没有展开讲,它是比 chmod 更细粒度的授权方式,可以给某个具体用户单独授权而不动属主属组。等基本命令熟练之后,再去接触 ACL 会很容易。
最后分享一个我养成的习惯:每次要改权限之前,先问自己三个问题——真正访问这个文件的进程是谁?它的属主应该是谁?它需要对哪些角色开放?把这三个问题想清楚,再决定用 chmod 还是 chown、用哪个值,往往比背下一百条命令更重要。文件权限这东西,命令很少,规则很死,真正难的是判断“这条路径上谁在访问、谁该有权限”的思维方式。希望你从这篇里带走的不仅是几个命令,而是这条思考路径。