Shell 脚本执行 permission denied 报错怎么解决 chmod 无效?

文章导读
Shell 脚本 chmod 后仍报 permission denied,通常是因为文件系统挂载了 noexec 选项或 SELinux 策略拦截,而非文件权限位错误。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
A A

Shell 脚本 chmod 后仍报 permission denied,通常是因为文件系统挂载了 noexec 选项或 SELinux 策略拦截,而非文件权限位错误。

先说结论:chmod 无效多半是挂载选项或安全模块限制,不是权限位问题。

  • 先确认:检查文件系统挂载选项是否包含 noexec
  • 先处理:尝试用 bash 直接调用脚本或修改挂载参数
  • 再验证:重新执行脚本确认报错消失

命令速用版

# 检查当前目录挂载选项
df . | tail -1 | awk '{print $1}'
mount | grep 设备名

# 临时绕过执行权限限制
bash script.sh

# 查看 SELinux 状态
getenforce

为什么会这样

chmod 只能修改文件本身的权限位,无法覆盖文件系统挂载时的安全策略。

Linux 系统在执行二进制文件或脚本时,内核会先检查文件权限位(如 x 位),再检查文件系统挂载选项。如果挂载选项包含 noexec,内核直接拒绝执行该分区上的任何文件,无论 chmod 是否设置了执行权限。此外,SELinux 或 AppArmor 等安全模块可能根据上下文策略禁止特定路径的脚本执行,这也不会被 chmod 修正。

分步处理

按顺序排查挂载选项、安全模块和解释器调用方式,避免盲目修改权限。

步骤 1:检查挂载选项

使用 df 命令确认脚本所在分区,再用 mount 命令查看该分区选项。

df script.sh
mount | grep 分区设备名

如果输出中包含 noexec,说明该分区禁止执行文件。需要修改/etc/fstab 移除 noexec 选项并重新挂载,或将脚本移动到允许执行的分区。

步骤 2:检查 SELinux 状态

在 CentOS、RHEL 或 Fedora 系统上,SELinux 可能拦截执行。

getenforce
sestatus

Shell 脚本执行 permission denied 报错怎么解决 chmod 无效?

如果状态为 Enforcing,尝试临时设置为 Permissive 测试是否为策略问题。生产环境建议调整 SELinux 上下文而非直接关闭。

步骤 3:更换执行方式

如果无法修改挂载选项,使用解释器直接调用脚本,这种方式只需要读权限而不需要执行权限。

bash script.sh
sh script.sh

怎么验证是否生效

执行操作后,直接运行脚本并观察退出状态码和输出内容。

./script.sh
echo $?

如果退出状态码为 0 且脚本内容正常输出,说明问题解决。如果仍报错,检查系统日志/var/log/secure 或/var/log/audit/audit.log 查看拦截记录。

常见坑

  • NFS 或 Samba 挂载目录默认常带 noexec 选项,直接在该目录运行脚本必报错。
  • Docker 容器挂载卷时,宿主机的挂载选项可能透传到容器内,导致容器内 chmod 无效。
  • Windows 编辑的脚本带有 CRLF 换行符,可能导致解释器识别错误,报 permission denied 或 not found。
  • 目录本身缺少执行权限,即使文件有 x 位,用户无法进入目录也无法执行文件。

常见问题

chmod 777 为什么还是无法执行?

因为文件系统挂载了 noexec 选项,内核层直接拦截执行请求,权限位再生效也没用。

如何临时解决 noexec 限制?

使用 bash script.sh 调用脚本,这种方式不需要文件具备执行权限,只需要读权限。

SELinux 拦截怎么查看原因?

查看/var/log/audit/audit.log 日志,搜索 denied 关键字,或使用 audit2why 工具分析策略。

为什么目录权限也会影响脚本执行?

Linux 执行文件需要遍历路径,如果父目录缺少执行权限,用户无法进入目录读取文件。