2026/10/24 7:43:57

Linux rwx权限详解:文件与目录语义差异及排错实践

Linux rwx权限详解:文件与目录语义差异及排错实践 Linux 里rwx这三个字母放到文件和目录上完全不是一回事。同样是r在文件上是能不能读内容在目录上是能不能列出里面有哪些文件同样是x在文件上是能不能当程序执行在目录上是能不能进入这个目录。很多人第一次遇到Permission denied就卡在这里明明ls -l看着权限挺正常cat却读不了明明文件是777非属主用户还是删不掉。问题不在文件本身而在它所在的目录。这篇文章把这件事拆开讲清楚。先从ls -l的权限位读法讲起再搭一个干净的测试环境把文件上的r、w、x逐个验证一遍再把目录上的r、w、x逐个验证一遍中间穿插组合矩阵和真实报错。后面继续讲数字权限、chmod、chown、umask、setuid/setgid/sticky 这几位特殊权限再给一份按现象查原因的排错表最后落到工程上的几条实践建议。适合谁看刚接触 Linux 的后端开发、需要维护服务器的运维同学、经常在容器里改挂载目录权限的人以及被Permission denied反复折腾过的读者。全文的命令都可以直接复制执行实验目录统一放在/tmp/perm_lab不会污染系统目录。1. rwx 权限位速览文件与目录的语义差异先给结论再讲细节。Linux 的权限模型把每个文件的访问者分成三类所有者owner简写 u、所属组group简写 g、其他人others简写 o。每一类都有一套独立的rwx三位权限合起来就是ls -l里那串 9 个字符。这套模型对普通文件和目录一视同仁地套用但同一个字母在两种对象上表达的能力完全不同这是所有混淆的源头。文件上的三位权限含义比较直观权限位对文件的作用典型操作r读取文件内容cat、less、head、grep、被程序读取w修改文件内容echo 、vim保存、sed -i、截断写入x把文件当作程序执行./script.sh、执行二进制、被解释器加载目录上的三位权限则是一套目录项管理的语义重点在于目录本质是一个名字到 inode 的映射表权限位对目录的作用典型操作r列出目录内的条目名称ls dir、find dir -maxdepth 1w在目录内创建、删除、重命名条目touch、mkdir、rm、mv、lnx进入目录、穿透目录访问其下条目cd dir、cat dir/file、stat dir/file把这两张表放在一起看一个关键差异就出来了目录的w权限管的是目录项的增删改而不是目录里文件的内容。也就是说一个用户能不能删除某个文件取决于他对该文件父目录有没有w和x跟文件自己的w位没有关系。这一点在后面第 5 节会用实验完整验证也是日常排障里最高频的认知偏差。还有一个容易被忽略的细节目录的x权限是穿透权限。没有x即使你有r能看到文件名也无法cd进去无法cat里面的文件无法stat里面的 inode。反过来只有x没有r你进得去、能访问已知路径下的文件但ls会失败。这四种组合r、x、rx、无在实际使用中都有明确用途后面会给完整矩阵。2. ls -l 输出怎么读权限串、链接数、属主属组在动手做实验之前先把ls -l的每一列讲清楚不然后面看到输出还是懵。执行一条命令输出大致长这样ls -l /etc/passwd /etc/shadow /tmp-rw-r--r--. 1 root root 2846 Mar 12 09:11 /etc/passwd ----------. 1 root root 1523 Mar 12 09:11 /etc/shadow drwxrwxrwt. 5 root root 4096 Mar 14 20:02 /tmp第一列是权限串共 10 个字符。第 1 位是文件类型-表示普通文件d表示目录l表示符号链接c表示字符设备b表示块设备s表示 socketp表示命名管道。第 2 到第 4 位是所有者权限第 5 到第 7 位是所属组权限第 8 到第 10 位是其他人权限。上面的/etc/passwd是-rw-r--r--翻译过来就是所有者可读写、组可读、其他人可读。第二列是硬链接数对目录来说它至少是 2.和父目录里的条目每多一个子目录就加 1。第三列是所有者第四列是所属组第五列是大小目录的大小通常是 4096 字节指的是目录项占用的块不是里面文件的总大小后面是修改时间和路径。注意/etc/shadow那串----------只有 root 能读写普通用户连看都看不到内容这就是r位在文件上的直接体现。再补充一个更好用的命令stat它会把八进制权限和符号权限一起打出来stat -c %A %a %U:%G %n /etc/passwd /etc/shadow /tmp-rw-r--r-- 644 root:root /etc/passwd ---------- 000 root:root /etc/shadow drwxrwxrwt 1777 root:root /tmp%a输出的是八进制形式/tmp显示成1777多出来最前面的那个1就是粘滞位sticky bit这个在第 7 节详细讲。日常排障时建议养成用stat看权限的习惯它比ls -l更精确尤其是在排查特殊权限位和 ACL 的时候。3. 测试环境准备造一个干净的权限实验室讲权限最怕纸上谈兵所以下面所有结论都用命令验证一遍。准备一台 Linux 机器Ubuntu 20.04 及以上或 CentOS 7 及以上都行物理机、虚拟机、云主机、本地 WSL 都可以。需要 root 和一个普通用户下面的例子用tester作为普通用户如果你的系统里没有用useradd建一个。先建实验目录和测试用户# 需要 root 权限执行 useradd -m tester 2/dev/null || echo tester 已存在 mkdir -p /tmp/perm_lab cd /tmp/perm_lab # 造一个测试文件和一个测试目录 echo hello permission file.txt mkdir dir_a echo inside dir_a dir_a/inner.txt # 确认实验对象 ls -l /tmp/perm_lab-rw-r--r-- 1 root root 17 Mar 14 20:10 file.txt drwxr-xr-x 2 root root 24 Mar 14 20:10 dir_a默认情况下root 创建的普通文件是644目录是755这是由umask决定的后面第 6 节会讲。现在文件属主是 roottester属于 othersothers 位是r--所以tester能读不能写。这个基线正好用来做后面的对照实验。还有一个必须注意的环境细节如果你登录的账号本身是 root很多实验会看起来都成功因为 root 几乎不受权限位限制。所以后面测权限时要么用su - tester切过去要么用sudo -u tester单条命令执行。建议统一用sudo -u tester不切换会话输出更干净# 用 tester 身份执行单条命令推荐这种写法 sudo -u tester cat /tmp/perm_lab/file.txt # 或者切到 tester 的会话里做连续操作 su - tester4. 文件权限实测r、w、x 分别能做什么这一节把文件上的三位权限逐个验证。每次改权限都用chmod测试用sudo -u tester以普通用户身份执行观察返回结果。4.1 文件 r 权限能不能读内容先把文件权限收紧到000只给 others 读权限其他都去掉。为了干净直接改成004只有其他人可读chmod 004 /tmp/perm_lab/file.txt stat -c %A %a %U:%G %n /tmp/perm_lab/file.txt-------r-- 004 root:root /tmp/perm_lab/file.txt现在tester能读不能写验证一下sudo -u tester cat /tmp/perm_lab/file.txthello permission读成功。再把读权限去掉改成000再试一次chmod 000 /tmp/perm_lab/file.txt sudo -u tester cat /tmp/perm_lab/file.txtcat: /tmp/perm_lab/file.txt: Permission denied报错是Permission denied不是No such file or directory。这个区别很重要如果报的是没有这个文件说明问题出在路径解析上多半是某个上级目录缺x如果是权限不够说明路径能走到卡在目标文件自身的权限上。排障时先看报错类型能省一半时间。值得单独提一句的是r位对读取是统一的但对执行没有帮助。有些人以为r就代表文件可以跑其实脚本能不能执行取决于x位而解释器bash、python读取脚本内容时才需要r。所以一个--x的脚本文件如果你用bash script.sh方式调用会因为 bash 读不到内容而失败只有./script.sh这种方式才只看x。4.2 文件 w 权限能不能改内容继续测写权限。把文件恢复成644让tester属于 others此时 others 只有rchmod 644 /tmp/perm_lab/file.txt sudo -u tester sh -c echo append /tmp/perm_lab/file.txtsh: 1: cannot create /tmp/perm_lab/file.txt: Permission denied写入失败符合预期。现在把 others 的写权限打开改成646chmod 646 /tmp/perm_lab/file.txt sudo -u tester sh -c echo append line /tmp/perm_lab/file.txt cat /tmp/perm_lab/file.txthello permission append line写入成功。这里有个细节需要注意是追加写不会截断如果用覆盖写同样是看w权限。但vim这类编辑器的行为和重定向不一样它通常是写临时文件再 rename所以在某些目录权限受限的场景下vim保存会失败并提示只读而echo 却可能成功。这不是权限模型不一致而是编辑器自己做了保护性判断排障时不要被这个现象带偏。还要提醒一个常见误区给文件加了w权限不代表别人能删掉它。删除操作检查的是父目录的w权限这一点第 5 节会专门验证。4.3 文件 x 权限能不能作为程序执行x权限在文件上专门管能不能被当作程序启动。Linux 判断一个文件是不是可执行看的就是x位跟文件扩展名没有关系。准备一个脚本验证cat /tmp/perm_lab/hello.sh EOF #!/bin/sh echo script executed by $(id -un) EOF chmod 644 /tmp/perm_lab/hello.sh sudo -u tester /tmp/perm_lab/hello.shbash: /tmp/perm_lab/hello.sh: Permission denied644没有x直接执行被拒绝。加上xchmod 755 /tmp/perm_lab/hello.sh sudo -u tester /tmp/perm_lab/hello.shscript executed by tester执行成功。这里可以顺带验证一个反差即使没有x用解释器显式调用通常也能跑因为这时只要求解释器能读到文件内容chmod 644 /tmp/perm_lab/hello.sh sudo -u tester sh /tmp/perm_lab/hello.shscript executed by tester这就是x和r的分工x决定能不能被内核当程序加载r决定能不能被读取内容。对于一个744的脚本所有者能直接跑其他人只能读、不能跑对于一个711的脚本其他人能跑但读不到内容所以不能复制、不能查看源码。生产环境上把脚本设成711其实是保护源码的一种土办法代价是排查问题时看不到内容可维护性变差一般不建议。4.4 文件权限的最小充分组合把上面的实验收一收可以归纳出几种常见组合的用途八进制符号常见用途600rw-------私钥、.env、凭据文件只有属主可读写644rw-r--r--普通配置文件、静态资源所有人可读、属主可写640rw-r-----属组内可读的配置如日志、数据库配置文件660rw-rw----属组内协同编辑的文件700rwx------私有脚本、私有目录755rwxr-xr-x可执行脚本、可被所有人读取的目录750rwxr-x---属组内可执行的脚本、属组内可进入的目录777rwxrwxrwx谨慎使用几乎总是过宽600和644是最常打交道的两种。像 SSH 私钥这类文件OpenSSH 会强制检查权限如果被改成644会直接拒绝使用并提示 UNPROTECTED PRIVATE KEY FILE这不是 OpenSSH 多事而是权限模型本来就不该让其他人读到私钥内容。类似的检查在很多工具里都有遇到这类报错先stat看一眼八进制权限比翻文档快。5. 目录权限实测r、w、x 的真实边界这一节是全文的重点。目录的权限语义和文件完全不同而且组合起来的表现更反直觉必须靠实验建立直觉。5.1 目录 r能不能列出目录内容先看r在目录上的作用。把dir_a改成744也就是 others 只有rchmod 744 /tmp/perm_lab/dir_a stat -c %A %a %n /tmp/perm_lab/dir_adrwxr--r-- 744 /tmp/perm_lab/dir_a现在tester是 others有r没有x。试两件事一件是ls一件是直接读里面的文件sudo -u tester ls /tmp/perm_lab/dir_a sudo -u tester cat /tmp/perm_lab/dir_a/inner.txtinner.txt cat: /tmp/perm_lab/dir_a/inner.txt: Permission denied结果很典型ls成功能看到文件名inner.txtcat失败。原因就是ls只需要目录的r权限读取目录项列表而cat需要先穿过目录找到inner.txt的 inode这一步需要目录的x权限。只有r没有x的目录能看到名字但拿不到内容也进不去。这种权限在现实中几乎不会主动配置因为它既不安全也不实用。但它解释了一个常见报错cat: xxx: Permission denied而你ls明明看得到文件八成就是上级某个目录缺x。5.2 目录 x能不能进入和穿透把权限反过来只给x不给r改成711chmod 711 /tmp/perm_lab/dir_a stat -c %A %a %n /tmp/perm_lab/dir_a sudo -u tester ls /tmp/perm_lab/dir_adrwx--x--x 711 /tmp/perm_lab/dir_a ls: cannot open directory /tmp/perm_lab/dir_a: Permission deniedls失败因为列目录要r。但此时如果知道确切的文件路径依然能访问sudo -u tester cat /tmp/perm_lab/dir_a/inner.txt sudo -u tester cd /tmp/perm_lab/dir_a pwdinside dir_a /tmp/perm_lab/dir_a能读、能cd。这就是x的本质它是路径穿透权限。只要路径上的每一级目录都有x你就能走到目标文件至于中间目录里还有什么别的文件你不需要知道也不能列出来。这种配置在 Web 服务器上非常常见把静态目录设成711外部进程可以通过已知 URL 路径取到具体文件但列不出目录清单起到一定的信息隐藏作用。这里要强调一个高频事故场景/home/xxx目录默认是700或750。当 Nginx、PHP-FPM、Tomcat 这类以独立用户运行的服务需要读取用户家目录下的文件时经常报Permission denied而文件本身明明是644。原因就是/home/xxx这个目录对服务用户没有x路径走不通。解决方式是给目录补x比如chmod ox /home/xxx或者更稳妥地把资源移出用户家目录放到/var/www这类专用位置。5.3 目录 w创建和删除看的是父目录这是权限模型里最容易被误解的一点。先看一个反直觉的现象文件权限设成000但父目录可写文件照样能被删除。chmod 755 /tmp/perm_lab/dir_a chmod 000 /tmp/perm_lab/dir_a/inner.txt sudo -u tester rm -f /tmp/perm_lab/dir_a/inner.txt ls -l /tmp/perm_lab/dir_atotal 0文件被删掉了尽管它的权限是000。原因在于rm操作的本质是从父目录的目录项里移除一条记录修改的是父目录这个数据结构跟文件自身权限无关。所以判断能不能删看的是父目录有没有w写目录项和x定位到条目。反过来验证文件是777但父目录不可写也删不掉。echo test /tmp/perm_lab/dir_a/locked.txt chmod 777 /tmp/perm_lab/dir_a/locked.txt chmod 755 /tmp/perm_lab/dir_a sudo -u tester rm -f /tmp/perm_lab/dir_a/locked.txtrm: cannot remove /tmp/perm_lab/dir_a/locked.txt: Permission denied755的目录others 只有r-x没有w所以删不掉。给目录加上wchmod 757 /tmp/perm_lab/dir_a sudo -u tester rm -f /tmp/perm_lab/dir_a/locked.txt echo exit code: $?exit code: 0删除成功。这个实验的意义在于纠正一个非常普遍的误解文件的权限位保护不了文件不被删除保护文件不被删除的是目录权限。想阻止别人删你的文件正确做法是把父目录设成不可写而不是把文件改成444或者000。顺带说明目录的w单独存在没有意义它必须配合x才能生效。因为要在目录里创建文件得先进得去。一个200权限的目录实际上什么也做不了。所以w和x在目录上基本是绑定使用的-wx3和r-x5、rwx7才是有效组合。5.4 目录 r、x 组合矩阵把四种组合摊开看一目了然目录权限符号能ls能cd能访问已知路径文件能创建/删除0---否否否否1--x否是是否2-w-否否否否3-wx否是是是4r--是否否否5r-x是是是否6rw-是否否否7rwx是是是是2、3、6这几种带w不带x的组合没有实际意义4只能看名字不能访问内容实际场景里基本只有1、5、7三种会在生产环境出现。5r-x就是最常见的目录权限7用于需要协同写入的共享目录1用于隐藏目录内容但保留路径可达。6. 数字权限、chmod、chown 与 umask前面一直用八进制改权限这里把规则补全。rwx三位按r4、w2、x1相加得到 0 到 7 的单个数字三组拼起来就是三位八进制数数字符号说明0---无权限1--x仅执行 / 穿透2-w-仅写3-wx写 执行4r--仅读5r-x读 执行6rw-读 写7rwx全部权限chmod支持两种写法八进制和符号。八进制适合精确定位到某个值符号适合在现有基础上增删某一位各有适用场景# 八进制直接设定完整权限 chmod 640 /tmp/perm_lab/file.txt # 符号在现有基础上操作 chmod ux /tmp/perm_lab/hello.sh # 属主加执行 chmod g-w /tmp/perm_lab/file.txt # 属组去掉写 chmod or /tmp/perm_lab/file.txt # 其他人设为只读 chmod ar /tmp/perm_lab/file.txt # 所有人加读 chmod urwx,grx,o /tmp/perm_lab/hello.sh # 一次设三组符号写法里的a代表 all等价于ugo是设为精确值和-是增量调整。批量修权限时比和-更安全因为它不依赖当前状态结果是确定的。关于chmod -R一定要谨慎。它是递归地把同一个权限模式套用到目录下所有对象而文件需要x、目录需要x的语义完全不同。一条chmod -R 777 /var/www会把所有 PHP 文件、所有静态资源全变成可执行既破坏语义也埋下安全隐患。正确的递归写法应该分开处理# 目录统一 755文件统一 644这种写法比 chmod -R 777 安全得多 find /var/www -type d -exec chmod 755 {} \; find /var/www -type f -exec chmod 644 {} \; # 只对 shell 脚本补执行位 find /var/www -type f -name *.sh -exec chmod 750 {} \;chown负责改归属chgrp负责改属组chown也能一次改两者chown tester /tmp/perm_lab/file.txt chown tester:users /tmp/perm_lab/file.txt chown -R tester:tester /tmp/perm_labumask决定新建文件和目录的默认权限。它不是直接设置权限而是从基准值里扣掉某些位。文件基准是666目录基准是777umask的位会从基准里被减去。常见的umask 022意味着文件666 - 022 644目录777 - 022 755。如果umask是027那文件是640目录是750。验证方式很简单umask touch /tmp/perm_lab/newfile.txt mkdir -p /tmp/perm_lab/newdir stat -c %A %a %n /tmp/perm_lab/newfile.txt /tmp/perm_lab/newdir-rw-r--r-- 644 /tmp/perm_lab/newfile.txt drwxr-xr-x 755 /tmp/perm_lab/newdirumask可以在~/.bashrc、/etc/profile或服务的 systemd unit 里设置属于从源头控制默认权限的手段比事后chmod补救更可靠。7. 特殊权限位setuid、setgid、sticky权限串一共 10 位前面用了 9 位还有一组特殊位会覆盖在x的位置上显示。这是权限管理里必须知道的一块因为它在系统里到处都是。特殊位数值出现在文件 / 目录上的作用setuid4000属主x位显示为s或S文件以文件属主身份执行目录Linux 上基本无效setgid2000属组x位显示为s或S文件以文件属组身份执行目录新建文件继承目录属组sticky1000其他人x位显示为t或T目录只有文件属主或 root 能删除该文件/usr/bin/passwd是最经典的 setuid 例子。普通用户改自己的密码需要写/etc/shadow而那个文件是000普通用户根本没权限。之所以能改成功是因为passwd这个二进制带了 setuid 位运行时临时获得 root 身份stat -c %A %a %U:%G %n /usr/bin/passwd-rwsr-xr-x 4755 root:root /usr/bin/passwd注意属主位显示的是rws而不是rwx那个s就是 setuid 的标志。如果大写S说明 setuid 位设了但对应的x位没设这个组合实际上是失效的属于配置错误。setgid 在目录上的用法更实用给一个共享目录设 setgid 后里面新建的文件和子目录会继承父目录的属组而不是创建者自己的主组。团队协作目录基本都这么配mkdir -p /srv/team_share chown :devteam /srv/team_share chmod 2775 /srv/team_share stat -c %A %a %U:%G %n /srv/team_sharedrwxrwsr-x 2775 root:devteam /srv/team_share属组位的s出现表示 setgid 生效。这样devteam组里任何人新建文件属组都是devteam组内成员都能读写不需要每次手动chgrp。sticky 位最典型的场景就是/tmp。/tmp是1777所有人都能写但每个人只能删自己的文件靠的就是粘滞位stat -c %A %a %n /tmp mkdir -p /tmp/perm_lab/shared chmod 1777 /tmp/perm_lab/shared sudo -u tester touch /tmp/perm_lab/shared/tester_file sudo -u nobody touch /tmp/perm_lab/shared/nobody_file sudo -u nobody rm -f /tmp/perm_lab/shared/tester_filedrwxrwxrwt 1777 /tmp rm: cannot remove /tmp/perm_lab/shared/tester_file: Permission deniednobody删不掉tester的文件尽管目录是777。这就是粘滞位的价值在所有人可写的目录里加一道只能删自己的限制。共享上传目录、临时交换目录都应该配1777。8. 常见 Permission denied 排查表权限问题报错信息往往很模糊但结合操作类型和对象类型基本能定位到原因。下面这张表按现象整理覆盖日常遇到的大部分场景问题现象可能原因排查方式解决方案ls能列出文件cat报 Permission denied上级目录缺x穿透权限逐级stat -c %A %a %n检查路径上每一级目录给缺失的目录补x如chmod oxls dir报 cannot open directory目录缺r权限stat看目录权限位补r或用已知路径直接访问文件是777却删不掉父目录缺w权限stat看父目录权限给父目录补w或换用有权限的目录cd进不去目录目录缺x检查目录 others/group 位补x权限脚本./run.sh报 Permission denied缺x位ls -l run.shchmod x run.sh脚本./run.sh报 bad interpretershebang 路径错误或文件是 CRLF 换行head -1 run.sh、file run.sh修正 shebangdos2unix转换换行SSH 私钥无法使用提示 UNPROTECTED PRIVATE KEY私钥权限过宽stat看权限chmod 600 id_rsa服务读不到用户家目录下的文件家目录700服务用户无x检查/home/xxx权限移资源到/var/www或补ox容器内写挂载目录失败容器内 UID 与宿主目录属主不匹配id对比容器内外 UID看宿主目录属主对齐 UID或调整目录属主/权限共享目录新建文件属组不对目录未设 setgidstat看是否有schmod 2775并设好属组所有人都能删别人文件共享目录缺粘滞位stat看是否有tchmod 1777root 也执行不了某个文件文件所有x位全被去掉stat确认root 也至少需要一个x位补上即可最后一条值得展开说。很多人以为 root 完全不受权限约束其实在执行文件这一件事上是有例外的如果文件三个x位全是0root 也会被拒绝执行。读、写文件 root 确实可以无视权限位但执行不行。所以在000权限的文件上哪怕用 root 也会报Permission denied需要先补一个x位。这个细节在排查我是 root 为什么也跑不了的时候很有用。另外容器环境里的权限问题往往更绕。Docker 默认以 root 运行但很多镜像为了安全会切到非 root 用户此时容器内的 UID 和宿主目录的属主 UID 对不上写挂载卷就会失败。排查方法是分别在容器内和宿主机执行id对比 UID然后决定是调整宿主目录属主还是在启动时用--user指定 UID。9. ACL 与 sudo权限不够时的两种补充手段传统rwx模型只有三组身份遇到只给某一个人单独开权限的需求就没办法了。这时候有两个选择ACL 和 sudo用途不同不要混用。ACL 是在原有三组权限之外给特定用户或组单独授权属于权限模型的扩展# 查看 ACL getfacl /tmp/perm_lab/file.txt # 给 tester 单独授予读写权限 setfacl -m u:tester:rw /tmp/perm_lab/file.txt # 给 devteam 组授予只读权限 setfacl -m g:devteam:r /tmp/perm_lab/file.txt # 设置默认 ACL让目录下新建文件自动继承 setfacl -d -m u:tester:rw /tmp/perm_lab/dir_a # 撤销 setfacl -x u:tester /tmp/perm_lab/file.txt设了 ACL 的文件ls -l的权限串末尾会多一个例如-rw-rw-r--。看到这个符号就要想到还有 ACL 规则单纯看rwx是不够的必须用getfacl才能看到全貌。这是排查权限问题时很容易漏掉的一环。sudo 解决的是另一个问题临时提权执行某个命令。它和文件权限是两套机制sudo走的是/etc/sudoers配置不改文件的rwx位# 查看当前用户可用的 sudo 权限 sudo -l # 以指定用户身份执行命令不切换会话 sudo -u tester cat /tmp/perm_lab/file.txt # 编辑 sudoers务必用 visudo 做语法检查 visudo -c选择建议很明确需要某个用户长期访问某个文件或目录用 ACL 或调整属组需要某个用户临时执行某类管理命令用 sudo。不要用chmod 777去解决访问问题那是把权限模型整个放弃掉后续排查会更难。10. 落地实践几条能直接用的权限管理习惯把上面这些实验收成几条可以直接照做的习惯都是踩过坑之后总结出来的。第一条改权限之前先stat。不要凭ls -l的九位权限串下判断stat -c %a能一眼看出八进制值、特殊位和 ACL 标记。排查Permission denied时沿着路径从根到目标逐级stat找到第一个缺x的目录问题基本就定位了。这个动作花不了十秒比反复试错快得多。第二条永远不要用777解决问题。777意味着任何人都能改、任何进程都能写一旦出问题无法追溯而且会掩盖真正的权限配置错误。需要共享写权限用设置属组 2775 setgid需要临时目录用1777加粘滞位需要单人授权用 ACL。这三种方案都比777精确。第三条新建服务的目录结构时先定属主再定权限。顺序应该是chown把目录交给服务运行用户然后目录755、文件644需要写的目录单独给775。反过来做先chmod再chown容易在中间状态触发问题尤其是在服务已经启动的情况下。第四条敏感文件的权限要固定下来并做检查。私钥、.env、数据库配置、证书这类文件统一600或640。如果做镜像或部署包可以在构建阶段加一条校验权限过宽直接让流水线失败比事后审计有效。第五条chmod -R尽量不用用find分开处理目录和文件。前面给过写法这里再强调一次目录和文件的权限语义不同递归套用同一个值是错的。第六条排查容器内的权限问题时先确认 UID。容器里id一下宿主机id一下再stat挂载目录三个信息放在一起问题基本就浮出来了。很多容器写不进去的报障最后都落在 UID 不匹配上。第七条共享目录一律考虑粘滞位和 setgid。凡是多个用户都要往里写的目录1777或2775是起点而不是终点具体选哪个取决于要不要让用户之间互相删除文件。这个决定最好在设计阶段就定好别等出事再补。最后回到文章标题那句话rwx对文件和目录的作用完全不同而且目录的x比w更容易被忽略。记住两个判断就够用——能不能访问某个文件看路径上每一级目录有没有x能不能删除某个文件看父目录有没有w和x。这两条覆盖了日常八成的权限困惑遇到更复杂的场景再回来翻第 5 节的组合矩阵和第 8 节的排查表。