符号模式、八进制、–reference 参照文件,就是 chmod 手册语法里并列的三种写法。各适合什么场景、有哪些坑,均在 WSL 实测后写成。
一、三种写法对号入座,八进制怎么算
chmod 手册页的 SYNOPSIS 同时列了三种用法:符号模式(MODE)、八进制数字(OCTAL-MODE)、–reference=RFILE [1]。日常怎么选:
| 写法 | 例子 | 适合场景 | | — | — | — | | 符号模式 | chmod u+x s.sh | 只增删某一类位,其余不动 | | 八进制 | chmod 644 app.conf | 整体设定、脚本里成批处理 | | 参照文件 | chmod –reference=tmpl f | 照抄一个现成文件的权限 |
八进制每位是 r=4、w=2、x=1 的相加,依次对应属主、属组、其他人;可以在最前面再加一位,4、2、1 分别表示 setuid、setgid、sticky [3]。
: > f.txt && chmod 644 f.txt # rw-r--r--
chmod 755 f.txt # rwxr-xr-x
chmod u=rwx,go=rx f.txt # 符号写法,与上一行等价(实测同结果)
chmod 0755 f.txt # 三位前加 0,数字部分不变
chmod 888 f.txt # invalid mode:八进制只有 0-7,退出码 1
644 给普通文件、755 给程序和目录,是最常见的两组数,但注意数字是”整体覆盖”:它会把没写到的位全部清掉,增量调整请用符号写法。
二、前导位与特殊位:sticky 的保留规则跟 setuid 不一样
: > run.sh && chmod 4755 run.sh # -rwsr-xr-x
mkdir shared
chmod 2775 shared # drwxrwsr-x
chmod 1777 shared # drwxrwxrwt
chmod 755 shared # 实测:t 没了
stat -c '%a %A' shared # 755 drwxr-xr-x
setuid 让脚本以属主身份运行,setgid 目录里新建文件继承目录的属组,sticky 目录(如 /tmp)里谁的文件谁能删,这三条语义见手册 [1][4],执行层面的行为基于文档、本文未逐一实测。要实测出真差距的是”数字改写时特殊位保不保得住”:
也就是说,给共享目录补权限后,t 位要记得单独补一次 chmod 1777 或 +t。
三、符号写法:who、操作符,还有 umask 的暗中干扰
符号模式由三段组成:who(u 属主、g 属组、o 其他人、a 全部),操作符(+ 增、- 删、= 设定),再加权限字符 rwxXst;多段之间用逗号分隔 [1]。
: > f.sh # 新文件默认 644
chmod u+x f.sh # 变 744
chmod a-w f.sh # -r-xr--r--
chmod go-w f.sh # 本来就没有 w:无变化,退出码仍 0
mkdir -p conf.d && : > conf.d/plain.conf && : > conf.d/keep.sh
chmod 644 conf.d/plain.conf && chmod 755 conf.d/keep.sh
chmod -R a=rX conf.d # 目录和"本来可执行"的文件才有 x
a=rX 实测结果:conf.d 变 555,plain.conf 变 444,原本 755 的 keep.sh 保住 x 变 555。大写 X 的含义是”仅当目录或文件原本任一类有 x 才给 x”,给配置树批量加可读时比小写 x 安全 [3][2]。
另一个不显眼但会白跑命令的点:省略 who 时(如 chmod +w),手册明确”等效 a,但 umask 里置位的权限不受影响” [3]。实测:umask 022 下对 600 的文件跑 chmod +w,纹丝不动;改成 umask 000 再跑变 622;而写 a+w 就不受 umask 影响。脚本里要精确放权,把 who 和 a 写全。
四、参照写法 –reference:照抄权限
: > app.conf && chmod 640 app.conf
: > nginx.conf && : > proxy.conf
chmod --reference=app.conf nginx.conf proxy.conf
chmod -c --reference=app.conf proxy.conf
# mode of 'proxy.conf' changed from 0644 (rw-r--r--) to 0640 (rw-r-----)
–reference 把参照文件的权限整套复制过来,不用换算数字;手册注明参照文件若是软链接,取它指向文件的权限 [2]。实测两个文件都变 640;-c 会打出 changed from 明细,同权限重复执行则保持静默、退出码 0,想看 retained 行要换 -v [4]。参照文件本身是软链接的场景也实测通过,跟随指向取目标权限。批量对齐同一套权限、或恢复前先拿标准模板文件兜底,这条命令比挨个背八进制稳。
五、软链接、递归和以破折号开头的文件名
: > real.txt && ln -s real.txt link.txt
chmod 600 link.txt # 实际改的是 real.txt;link 本身仍 lrwxrwxrwx
chmod -h 600 link.txt # Ubuntu 24.04 实测报 invalid option -- 'h'
mkdir logs && ln -s ../real.txt logs/inner.txt
chmod -R go-rwx logs/ # 递归不跟进软链接指向的文件(实测)
: > ./-w
chmod -- -w ./-w # 文件名以 - 开头:模式前插 -- 再改(实测)
GNU 版 chmod 不改软链接本身,而是改它指向的文件;递归时忽略途中遇到的软链接,但命令行上直接给出的软链接仍会跟进指向目标 [2]。手册页里的 -h/–no-dereference 注明只在支持 lchmod 的系统可用,多数 Linux 上软链接自身权限本就被忽略 [1][4]——实测 Ubuntu 24.04 的 chmod(coreutils 9.4)根本没有 -h 这个选项,抄了 chmod -h 的教程会直接报错,不用纠结。文件名以 – 开头时按手册示例先写 — [2]。另外实测:非属主的普通用户 chmod 别人的文件报 Operation not permitted,chown 给该用户后自己就能改,这是”改不了权限”类求助的第一嫌疑。
六、撤销、回滚与排错速查
chmod 没有 undo。稳妥流程:动手前先 stat -c '%a %n' 目标/* > /tmp/perm.bak 记录现值(实测可用),再改;恢复时按记录逐行改回,或从标准模板文件 chmod --reference=模板 目标 整体复原。递归操作(chmod -R、777)动手前尤其要先备份权限记录,范围先在小目录验证再放大。
| 现象 | 原因 | 处理 | | — | — | — | | invalid mode: ‘888’ | 数字模式是八进制,只认 0-7 | 检查是否误用十进制 | | invalid mode: ‘u+x,’ | 符号段用逗号分隔,结尾多逗号非法 | 删掉末尾逗号(实测) | | chmod +w 没反应 | 省略 who 时被 umask 屏蔽 | 显式写 a+w | | invalid option — ‘h’ | 该发行版的 chmod 未编译 -h | 无需改软链接本身,Linux 会忽略其权限 | | 改权限报 Operation not permitted | 非属主且非 root | 由属主或 root 执行 | | 目录突然不能写文件 | = 形式或数字清掉了 sticky/写位 | 按 /tmp/perm.bak 恢复,必要时补 +t |
局限性:本文全部命令在 WSL2 ext4 上实测;NFS、drvfs 等特殊文件系统对权限位的处理(尤其 setuid/sticky 是否生效)未覆盖,RPM 系发行版未单独复测,操作前先在目标环境验证。
## 附:实测记录
参考资料
- [1] chmod(1) – Linux manual page (man7.org)(chmod(1) 手册页)
- [2] GNU Coreutils manual: chmod invocation(coreutils 手册)
- [3] File permissions (GNU Coreutils manual)(GNU 权限手册)
- [4] chmod(1) – coreutils – Debian bookworm man page(Debian chmod(1))
文中主要命令已在 WSL Ubuntu(24.04)实测并核对其在 Debian 系与通用发行版的文档口径。