chmod -R 755 /path 子目录未生效,因默认不跨挂载点、不处理ACL、不区分目录与文件权限;应改用 find 分别对目录设755、文件设644。

chmod 递归修改目录权限时为什么子目录没生效
直接用 chmod -R 755 /path 看似能改全树,但实际常遇到子目录仍是旧权限,尤其当目录里有符号链接、挂载点或权限被 ACL 锁定时。chmod -R 默认不跨越挂载点,也不处理 ACL 条目,更不会自动修正目录和文件的权限差异(比如目录该是 755,文件该是 644)。
常见错误现象:find 扫出来的子目录 ls -ld 显示权限没变;或者只改了第一层,深层嵌套跳过。
- 确认是否挂载子目录:用
df -h .查当前路径所在文件系统,若子目录属于另一设备,-R默认不进去 - 检查是否存在 ACL:运行
getfacl /path,若有user::/group::外的条目,chmod不会清除它们 - 区分目录与文件:直接
chmod -R会把 .php 文件也设成 755,执行风险高
用 find + chmod 分别设置目录和文件权限
这才是安全可控的全目录树权限修正法。核心思路是:先批量找目录、统一设为 755;再单独找常规文件,设为 644;跳过符号链接和特殊文件。
实操命令(以 web 根目录为例):
立即学习“PHP免费学习笔记(深入)”;
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
说明:
-
-type d确保只匹配目录,避免误改文件执行位 -
-exec chmod ... {} \;比xargs更稳妥,兼容含空格或特殊字符的路径 - 如需排除某子目录(如
cache/),加-not -path "./cache/*" - 若要限制深度(防误伤上级目录),可加
-maxdepth 3
PHP 中用 recursiveDirectoryIterator 递归改权限
纯 PHP 实现适合集成进部署脚本或后台工具,可控性更强,还能加日志、跳过只读文件、捕获 chmod() 失败原因。
关键点:
- 必须用
RecursiveDirectoryIterator+RecursiveIteratorIterator遍历,不能靠scandir()手写递归——后者易栈溢出且难处理权限拒绝 - 对每个
SplFileInfo对象,先用isDir()判断类型,再调chmod() -
chmod()返回false时不报错,需手动检查:if (!@chmod($file, $mode)) { error_log("chmod failed: $file"); }
简例:
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('/var/www/html', FilesystemIterator::SKIP_DOTS));
foreach ($it as $file) {
if ($file->isDir()) {
@chmod($file->getPathname(), 0755);
} else {
@chmod($file->getPathname(), 0644);
}
}
chmod 777 是最危险的「快捷方式」
线上环境一旦对整个树跑 chmod -R 777,等于向所有用户开放写权限,Web 服务用户(如 www-data)可被利用篡改代码或上传木马。
真正需要放宽的通常只是特定目录,例如:
- 缓存目录:设
775+ 正确属组(如chgrp www-data cache/) - 上传目录:设
755或750,禁止执行位(即不用777或775的执行位) - 绝对不要给
.php、.env、config/加写权限
Linux 权限模型里,“可写”比“可读”危险得多,而递归操作放大的正是这个风险——改错一个顶层目录,整棵树就裸奔。











