Linux——权限 学习记录
干这行久了你会发现,Linux里十有八九的“诡异问题”,最后都能追溯到权限身上。不是服务起不来,是脚本没有执行权限;不是文件丢了,是目录没有写权限;不是配置改错了,是进程根本没权限读那个文件。权限这东西,刚接触时觉得就是chmod 777走天下,等真正部署一次服务、搭一次环境、被线上故障折腾几回,才会老老实实回来把它啃明白。
这篇文章是我自己学习Linux权限的一份完整记录,从最基础的rwx讲到SUID、ACL这些进阶玩法,把每个命令背后“为什么这么做”也一并讲清楚。适合刚入门Linux的同学系统过一遍,也适合有一定基础但总是“会用不会讲”的朋友查漏补缺。我尽量用大白话,把那些文档里写得绕来绕去的概念,掰开揉碎放在实际场景里。
1. 为什么Linux权限值得你认真学一遍
1.1 权限搞不懂,后面全是坑
很多人刚开始用Linux时,觉得权限就是个“附加题”。毕竟自己一个人用虚拟机,root用户想干嘛干嘛,chmod 777一敲,什么问题都没有了。但权限这东西,本质上和Linux的文件系统、多用户机制、进程模型深度绑定。你后面写脚本、部署网站、搭数据库、做自动化运维,每一个环节都会遇到权限问题。
举个最常见的例子:你用nginx运行一个Web服务,网页文件是root用户上传的,nginx工作进程以www-data用户运行,结果浏览器访问时一片403。这时候你才意识到,文件存在还不够,得让“别人”能读、能执行。这个“别人”是谁?权限模型里的“其他人(other)”说的就是这种情况。类似场景在配置cron定时任务、挂载磁盘、搭建Docker环境时还会反复出现。
我自己的体会是:权限不是一个可以绕开的点,它是Linux安全的基石,也是你从“会用Linux”走向“懂Linux”的必经门槛。早一点系统学一遍,后面踩的坑会少一半。
1.2 从ls -l输出说起
要理解权限,最好的切入点是终端里那一行ls -l的输出。随便找个文件看一眼:
$ ls -l /etc/passwd -rw-r--r-- 1 root root 2859 Nov 18 10:32 /etc/passwd这一行看起来简短,信息量却非常大:
-rw-r--r--:文件类型 + 权限位1:硬链接数量root root:所有者和所属组2859:文件大小(字节)Nov 18 10:32:修改时间/etc/passwd:文件路径
权限位那一串字符rw-r--r--,可以拆成四段来看。第一段是文件类型,-表示普通文件,d是目录,l是软链接,c是字符设备,b是块设备。后面九位每三位一组,依次是“所有者(u)”、“所属组(g)”、“其他人(o)”的权限。每组内部都按rwx顺序排列,出现字母表示有对应权限,-表示没有。
所以rw-r--r--的意思就是:所有者可读可写,所属组和其他人只能读。这个模型构成了Linux权限管理的基本框架,掌握了它,再看任何权限相关的问题都会一目了然。
2. 基本权限模型:rwx到底在管什么
2.1 读、写、执行,三类权限的含义
r、w、x代表三种基本操作权限,分别对应读、写、执行。这里要特别注意:同一个字母,作用在普通文件上和作用在目录上,含义是截然不同的。很多人第一次栽跟头就是因为分不清“文件权限”和“目录权限”。
普通文件上的权限容易理解:
r(读):能查看文件内容,比如cat、less、head都能正常工作w(写):能修改文件内容,比如vim编辑、用>重定向写入x(执行):能把文件当作命令或脚本运行
目录上的权限就有点绕了:
r(读):能读取目录里的文件名列表,也就是能ls看到有哪些文件w(写):能在目录里创建、删除、重命名文件或子目录x(执行):能“进入”目录,也就是能cd进去,并且能访问目录里文件的具体属性
关键点在于:目录的r权限管的是“能否列出文件名”,目录的x权限管的是“能否真正访问到文件本身”。如果你只有r没有x,你ls可以看到目录里有哪些名字,但cd进不去,也读不了文件内容,甚至ls -l查看详细属性都会被拒绝,因为读取文件的inode信息需要通过x权限。反过来,只有x没有r,你能进去,也能访问知道名字的文件,但没法列出目录里还有什么。
我见过最典型的案例是:有人把网站目录设成了755,文件也是644,但访问时依然报错No such file or directory,明明文件就在那。最终排查发现是中间某一层目录权限不足,nginx工作进程没有x权限无法穿越路径。记住这句话:要访问一个路径下的文件,路径上每一层目录都需要有执行权限。
2.2 三种身份:所有者、所属组、其他人
Linux是多用户操作系统,权限自然围绕“用户”来划分。每个文件都有三个身份维度:
- 所有者(user,缩写u):文件的创建者或通过
chown指定的人 - 所属组(group,缩写g):文件所属的用户组,组内所有成员共享这个权限
- 其他人(other,缩写o):既不拥有文件,也不在所属组里的所有用户
另外还有一个特殊身份:root(超级用户)。root几乎不受普通权限限制,它可以读写任何文件、进入任何目录。这一点既能救命也容易造成惯性思维——你用root排查问题没问题,但线上服务跑起来通常不是root,问题就暴露了。
判断一个进程能不能访问文件时,系统只认一个身份:进程的运行用户。具体判断顺序是:进程用户是否等于文件所有者?不等的话再看是否属于文件所属组?也不属于的话,就落到“其他用户”权限。这三选一,不会叠加,也不会取并集。这个逻辑虽然简单,但很多新手会误以为“我是所有者我有读,我又在组里我有写,那权限就是读+写”,其实不是,只看命中的第一顺位身份。
下面这张表是判断过程的直观展示:
| 判断顺序 | 条件 | 生效权限 |
|---|---|---|
| 1 | 进程用户 == 文件所有者 | 所有者权限位(u) |
| 2 | 进程用户 ∈ 文件所属组 | 所属组权限位(g) |
| 3 | 其他情况 | 其他人权限位(o) |
2.3 数字权限的由来:rwx二进制编码
聊到chmod 755这类命令,就绕不开数字权限。三位数字的权限其实是将每类身份的rwx权限看作一个二进制数:r代表4,w代表2,x代表1,相加起来得到0到7的十进制数字。
为什么恰好是4、2、1?因为在计算机底层,这三个权限位可以看作一个三位二进制数,从高到低分别是"读、写、执行"。有权限则该位为1,没有则为0。rwx全部开启就是111,转成十进制是7;rw-是110,转成十进制是6;r--是100,转成十进制是4。
这三种权限组合一共8种情况,从0到7:
| 数字 | 二进制 | 权限字符 | 含义 |
|---|---|---|---|
| 0 | 000 | --- | 无任何权限 |
| 1 | 001 | --x | 仅可执行 |
| 2 | 010 | -w- | 仅可写 |
| 3 | 011 | -wx | 可写、可执行 |
| 4 | 100 | r-- | 仅可读 |
| 5 | 101 | r-x | 可读、可执行 |
| 6 | 110 | rw- | 可读、可写 |
| 7 | 111 | rwx | 可读、可写、可执行 |
所以chmod 755就是把所有者设为rwx(7),所属组设为r-x(5),其他人设为r-x(5)。这个编码规则不会变,熟练之后看到644、600、755,脑子里应该立刻浮现出对应的权限字符,这是Linux操作的基本功。
3. 实操:chmod、chown的完整用法
3.1 chmod:数字法与符号法怎么选
chmod是修改权限的核心命令,支持两种语法风格:数字法和符号法。
数字法直接、高效,适合批量设置:
chmod 755 script.sh chmod 644 /etc/nginx/sites-available/app.conf chmod 600 ~/.ssh/id_rsa符号法则更直观,适合局部修改某个身份的权限:
chmod u+x script.sh # 给所有者加执行权限 chmod g-w file.txt # 去掉所属组的写权限 chmod o=r file.txt # 把其他人的权限设为只读 chmod a+rx app.sh # 给所有身份都加读和执行权限 chmod u=rwx,g=rx,o=rx app.sh # 等同chmod 755符号法里的操作符有三种:+增加权限、-移除权限、=直接赋值权限。我个人的习惯是:设置一个明确的权限状态用数字法,临时调整某个身份用符号法。两种方法不冲突,但建议至少把数字法练到条件反射,因为看脚本和配置文件时数字出现频率太高了。
这里提醒一句:别动不动就chmod 777。这相当于给所有用户完全控制权,等于把安全机制关掉了。临时调试可以用,生产环境必须避免。如果确需要让多个用户协作访问文件,正确做法是设置所属组并赋予组权限,而不是把“其他人”权限放开。
3.2 递归修改与链接文件的坑
目录下有成百上千个文件时,手动逐个改不现实,需要递归操作:
chmod -R 755 /var/www/html chown -R www-data:www-data /var/www/html-R参数会递归处理目录下所有文件和子目录。用起来很方便,但也有两个坑。
第一个坑:chmod -R把目录和文件设置成同一个权限往往不合理。目录需要x权限才能进入,但普通文件如果给了x权限,等于告诉别人“这个文件可以执行”,对于纯数据文件来说完全没有必要,而且会增加风险。更规范的做法是分开处理:
find /var/www/html -type d -exec chmod 755 {} \; find /var/www/html -type f -exec chmod 644 {} \;这也是很多部署脚本里的标准写法,目录统一755,文件统一644,兼顾功能与安全。
第二个坑:chmod -R默认不会穿透软链接(符号链接)。对软链接本身执行chmod通常会报错或者没实际效果,因为权限只能修改链接指向的目标文件,而不能修改链接自身。所以遇到软链接时,要么直接对目标文件操作,要么用chmod -R -L穿透到链接指向的文件,但这个参数容易误伤,建议还是手动梳理清楚再操作。
3.3 chown与chgrp:改所有者、改所属组
chmod只管权限位,不管是谁拥有文件。实际场景中,经常要把文件转交给另一个用户或组去管理,这时候用chown。
chown alice file.txt # 把所有者改为alice chown :devs file.txt # 只改所属组为devs chown alice:devs file.txt # 同时修改所有者和所属组 chown -R www-data:www-data /var/www # 递归修改整个目录注意chown后的用户和组名可以省略其一:只写alice表示修改所有者,所属组不变;只写:devs表示只修改所属组,所有者不变。这个特性在只想改组时很实用,不用先查原所有者。
chgrp命令只负责修改所属组,功能上chown :group等价,所以现在很多习惯直接用chown,chgrp用得少了。但它是老牌命令,脚本里见到也不奇怪。
一个日常高频操作是:需要普通用户管理某个目录下的文件,但目录又属于root。此时不应给普通用户sudo权限一放了之,而应该用chown把目录转移给该用户,或把目录所属组改成包含该用户的组,再配合chmod g+rwx。这样既满足需求,又把权限控制在了最小范围内。
3.4 umask:新建文件为什么不都是777
还有一个容易被忽略但非常重要的问题:为什么touch出来的新文件权限是644,而新目录是755?这两个数字不是系统默认写死的,而是由umask计算出来的。
umask是一个掩码,用来屏蔽掉那些“不应该默认授予”的权限位。查看当前值:
$ umask 0022计算规则并不复杂。对文件来说,系统默认基础权限是666(因为文件默认不给执行权限,这是出于安全设计);对目录来说,默认基础权限是777。然后用“基础权限去掉umask中出现的位”来得到最终权限。
umask为022时,转换为二进制就是000 010 010,表示将所属组的写权限(2)和其他人的写权限(2)屏蔽掉。所以新建文件是666 - 022 = 644,新建目录是777 - 022 = 755。实际上这个“相减”并不是简单的算术减,而是把umask中为1的位对应的权限清除。但由于权限位恰好是4、2、1这样的数,且没有跨位影响,直接做减法的结果也是对的。
如果想让新建文件对组内成员可写,可以把umask调成002:
umask 002 touch newfile.txt ls -l newfile.txt # -rw-rw-r-- 1 user user 0 ... newfile.txtumask只在当前Shell会话中临时生效,要永久修改可以写入~/.bashrc或/etc/profile。这个细节在多人协作、共享目录的工作流中很关键,很多人遇到“明明是我新建的文件,同事却改不了”的问题,根源往往就是umask设得太严。
4. 进阶内容:特殊权限、ACL与实战场景
4.1 SUID、SGID与Sticky Bit
基础权限之外,Linux还有三个特殊权限位。它们不常见,但在特定场景下是必需品,也是排查诡异问题时的重点怀疑对象。
SUID(Set User ID):当一个可执行文件设置了SUID位后,普通用户运行它时,进程的有效身份会临时变成文件所有者,而不是运行者自己。最典型的例子是/usr/bin/passwd:
$ ls -l /usr/bin/passwd -rwsr-xr-x 1 root root 64152 Nov 6 23:43 /usr/bin/passwd注意所有者权限位变成了rws,那个s就是SUID。普通用户执行passwd修改自己的密码时,需要写入/etc/shadow,而该文件只有root能写。如果没有SUID,普通用户根本没法改密码。这里SUID让程序可以在运行期间“借用”root身份完成必要操作,但命令结束后权限随之消失。
SUID设置方法:chmod u+s file,对应数字法chmod 4755 file中的4。生产环境中能不用就不用,因为SUID是提权漏洞的高发点,一旦可执行文件本身可写或有漏洞,攻击者很容易利用SUID获取root权限。
SGID(Set Group ID)作用类似,但针对的是所属组身份。对可执行文件来说,赋予SGID后运行进程会临时获得文件所属组的身份。对目录来说更常用:当目录设置了SGID后,在该目录内新建的文件或子目录,其所属组会自动继承父目录的所属组,而不是创建者的主组。这个特性非常适合团队共享目录。
设置方式:chmod g+s dir,数字法是chmod 2770 dir中的2。
Sticky Bit(粘滞位)则用在目录上。它规定:在这个目录里,只有文件所有者、目录所有者或root才能删除或重命名文件,其他人即使对这个目录有写权限也删不动别人的文件。最典型的例子是/tmp:
$ ls -ld /tmp drwxrwxrwt 1 root root 4096 ... /tmp注意其他人权限位变成了rwt,末尾的t就是Sticky Bit。它的存在让/tmp这样的人人可写的目录不至于变成“互删战场”。设置方式:chmod +t dir,数字法是chmod 1777 dir中的1。
三个位叠加在chmod的数字写法里,就是四位数字,比如4755表示包含SUID,2770表示包含SGID,1777表示包含Sticky Bit。也可以组合,比如6755表示同时有SUID和SGID。
4.2 ACL:更精细的权限控制
基本权限模型只能精确到“所有者、所属组、其他人”三个身份,这在复杂协作场景下不够用。假设你希望文件所有者是alice,同时允许bob和carol有读写权限,但不希望整个组都拿到权限,基本权限就做不到了,而ACL(Access Control List)正是为这种需求设计的。
查看文件是否有ACL:
getfacl demo.txt给特定用户或组设置ACL:
setfacl -m u:bob:rw demo.txt # 给bob读写权限 setfacl -m g:devs:rx demo.txt # 给devs组读和执行权限 setfacl -x u:bob demo.txt # 移除bob的ACL条目 setfacl -b demo.txt # 清除所有ACL条目 setfacl -R -m u:bob:rwx /shared/project # 递归设置设置ACL后,再执行ls -l,权限位末尾通常会多一个+标记:
-rw-rw-r--+ 1 alice devs 1024 ... demo.txtACL有一个被高频提及的特性:mask。简单理解,mask是一个“权限上限”,它约束了所有命名用户、所属组和命名组能获得的权限上限,但不影响文件所有者。也就是说,即使ACL里给bob设置了rwx,如果mask是r--,bob实际也只能读到,不能写和执行。这个机制容易让人困惑,但它是ACL安全性的关键一环。
用getfacl可以清晰看到mask值:
$ getfacl demo.txt # file: demo.txt # owner: alice # group: devs user::rw- user:bob:r-- group::rwx # effective: r-- mask::r-- other::r--这里group::rwx后面标注了effective: r--,说明实际生效权限被mask限到了只读。遇到ACL权限“怎么设都不生效”的问题时,第一反应就是查mask。
4.3 实战场景:Web目录部署的标准权限方案
理论讲了一堆,落到实际场景里看看怎么组合使用。以一个常见的Web部署为例:网站目录在/var/www/html,Web服务以www-data用户运行,团队里还有一个开发者账户alice需要更新代码。
第一步:确定目录归属。把目录的所有权和组都交给www-data:
chown -R www-data:www-data /var/www/html第二步:设置目录和文件的权限。目录要能穿越,文件对外可读,但只有所有者能改:
find /var/www/html -type d -exec chmod 750 {} \; find /var/www/html -type f -exec chmod 640 {} \;这里没给“其他人”任何权限,因为Web服务通过www-data组身份访问,实际命中的是组权限,不需要开放“其他人”。这比常见的755/644方案更严格,也更安全。
第三步:让alice也能更新文件。把alice加入www-data组:
usermod -aG www-data alice如果要让alice新建的文件也自动属于www-data组,避免“文件是alice建的,Web服务读不了”的尴尬,可以给目录加SGID:
chgrp www-data /var/www/html chmod g+s /var/www/html这样alice在目录里新建的任何文件,所属组都自动是www-data,再配合umask设置为002(保证组内有rw权限),整套协作流程就很顺了。
如果某个子目录需要bob单独访问,还可以加ACL兜底:
setfacl -R -m u:bob:rx /var/www/html/reports这套方案生产环境里跑得很稳。它的核心思想是:能分组的用组权限解决,个别特殊身份用ACL解决,实在没办法才考虑放开“其他人”。每一步都尽量收紧权限,而不是一放了之。
5. 常见问题与排查技巧
5.1 权限问题排查三板斧
权限问题的表现五花八门,但排查思路是固定的。我自己遇到权限相关故障时,基本就按下面这个顺序走。
第一,确认运行身份。服务是哪个用户跑的?是root、www-data,还是某个专用账号?查看进程运行用户可以用:
ps aux | grep nginx如果是systemd管理的服务,看看单元文件里的User=参数。
第二,检查完整路径上每一层目录的权限。文件最终能不被访问,取决于从根目录到文件本身的所有路径节点。可以用namei命令一键查看:
$ namei -l /var/www/html/reports/2024-01.xlsx f: /var/www/html/reports/2024-01.xlsx drwxr-xr-x root root / drwxr-xr-x root root var drwxr-xr-x root root www drwxr-x--- root www-data html drwxr-x--- alice www-data reports -rw-r----- alice www-data 2024-01.xlsx一层层看下来,哪一层权限不对一目了然。这个命令在排查“明明文件权限没问题,但就是读不了”的场景里非常高效。
第三,模拟目标身份验证。真正的验证不是看权限位,而是切换到那个身份去实际操作。比如怀疑www-data读不了文件,就直接切过去试试:
sudo -u www-data cat /var/www/html/2024-01.xlsx能读到,说明路径和权限都没问题;读不到,说明问题确实出在权限配置上。这套逻辑比对着ls -l猜要可靠得多,因为实际进程还会受ACL、mask、文件系统挂载选项等因素影响。
5.2 高频报错速查
| 报错信息 | 常见原因 | 处理方向 |
|---|---|---|
| Permission denied | 文件或目录权限不足 | chmod调整权限,或改用归属用户运行 |
| Operation not permitted | 通常是root权限不足(如挂载、chown) | 确认是否需要sudo |
| Cannot open file for writing | 对文件有写权限但目录无写权限(或反之) | 检查所在目录的写和执行权限 |
| No such file or directory | 路径中某层目录无执行权限 | 检查路径每一层的x权限 |
| Stale file handle | NFS等文件系统句柄失效 | 重新挂载或刷新文件句柄 |
| Text file busy | 可执行文件正在运行中被覆盖 | 不能直接覆盖运行中的二进制,先停进程或改文件名 |
排查时的一点实战经验:在文件系统层面确认一下磁盘是否真的挂了。有时Permission denied其实不是权限问题,可能是noexec、nosuid等挂载选项导致的。用mount命令查看当前挂载选项:
mount | grep /data如果挂载选项里有noexec,那你只能访问目录里的数据,但没法执行任何二进制文件,无论chmod怎么设都没用。
5.3 几个能救急的小命令
日常维护中这几个命令和参数会反复用到,值得记下来:
# 查看某个用户对文件的权限,比ls -l更直观 namei -l /path/to/file # 找出目录下所有有异常写的文件 find /var/www -type f -perm -o+w -ls # 找出所有设置了SUID的文件(安全检查用) find / -type f -perm -4000 -ls 2>/dev/null # 查看当前用户在目录里的实际权限 namei -m /some/directory/path # 递归设置目录和文件不同权限的标准姿势 find /data/web -type d -exec chmod 750 {} \; find /data/web -type f -exec chmod 640 {} \;find按权限查找这个技巧,在巡检系统是否有“权限过度开放”的文件时非常省力。比如上面找出所有other有写权限的文件,很多时候这就是安全隐患的源头。
写在最后的几个心得
这套东西我前前后后系统学了三遍,每次都是被生产环境的问题推着回来重看。第一遍只记住了chmod 755,第二遍搞明白了rwx和数字的对应,第三遍才真正理解SUID、SGID、ACL这些机制的存在意义。回头看,学习权限最好的方式不是背命令,而是带着场景去理解——为什么passwd有rws权限?为什么/tmp要设t权限?为什么共享目录要设g+s?每个特殊设计背后,都是为了解决一个真实问题。
最后分享一个小技巧:改任何权限之前,先想清楚“到底要给谁开什么权限”,而不是“现在报错了,试试777”。前者是管理思维,后者是碰运气思维。线上环境里多一份谨慎,少一次故障,这就是权限学习带给你最直接的回报。