ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

chmod +x 与 Linux 脚本执行权限:从 Permission denied 到彻底搞懂

chmod +x 与 Linux 脚本执行权限:从 Permission denied 到彻底搞懂 “脚本写了半天一运行就报 Permission denied是不是chmod x没加加了还是不行终端权限问题坑了多少刚入门的玩家。”——这是服务器、虚拟机、甚至树莓派上最常见的日常场面之一。我见过不少初学者把脚本放在 /tmp、从网上下个二进制、或者在自己目录里折腾一晚上最后发现就是少了执行位。这篇东西就把 Linux 脚本执行权限这件事讲透从权限位的底层逻辑到 chmod x 的具体写法再到那些“加了 x 还跑不起来”的血泪场景一次理清楚。这内容适合所有刚接触 Linux 常用命令的人也适合那些被 shell 脚本入门折磨过的运维和开发。你跟着把命令敲一遍理解了“为什么文件要有执行权限”后面写脚本、部署项目、跑定时任务都会顺很多。1. 先搞清楚权限这回事为什么脚本不能“双击即跑”1.1 权限位拆解rwx 到底在管什么Linux 里几乎每个文件都带一组权限标记。你用ls -l看一眼目录第一列长得像一串字符比如-rw-r--r--。第一个字符表示类型-是普通文件d是目录l是符号链接。后面每三个字符一组分别是当前用户、当前用户所在的组、以及其他人对这文件的操作能力。三组里的字母就那么三个r是读取w是改写x是执行。放到脚本文件上r表示你能看它的内容w表示你能编辑它x表示你能让系统把它当作程序跑起来。注意最后一组其他人默认一般只有r也就是别人可以读你的脚本但改不了也执行不了——这其实是系统在保护你避免你把一个含rm -rf的脚本摆在 /tmp 里结果谁路过都能触发一次灾难。很多教程会把执行权限形容成“门禁卡”这个类比挺准确。读权限好比你能隔着玻璃看到屋里有什么写权限好比你有钥匙能进去改东西执行权限则是门禁系统允许你“直接上车开走”。脚本和人一样得先拿到驾驶资格系统才让你上路。1.2 脚本文件为什么默认不给你执行权限大多数 Linux 发行版里新建一个文件默认权限是-rw-r--r--也就是 644。为什么不是 755核心原因只有两个字安全。一个刚从网上下载回来的脚本或者别人通过邮件发给你的附件如果自带执行权限你只要手一抖./script就跑了什么后果都可能发生。系统默认你不信任它等你主动授予权限后才放手给你用。另外有个隐藏因素叫umask。默认值通常是 022它会把新建文件的执行位直接清掉。你可以用umask命令查看当前值改成umask 002也不影响日常使用但记住一点**脚本从来都不是开箱即跑的这符合 Linux 的安全哲学。**很多从 Windows 转过来的用户在这里摔第一跤——Windows 桌面软件安装包天然带图标、能双击、能运行Linux 则明确区分“读、写、执行”三个动作。1.3 普通文件与脚本的差别普通文本文件给不给执行权限没什么意义比如 C 源码、配置文件、Markdown 笔记就算全给x系统也不知道怎么执行。脚本则不同它开头顶着一个特殊标记叫 shebang通常长成#!/bin/bash。系统看到这个标记就知道应该调用/bin/bash这个程序来逐行解释执行文件里的命令。这里有个容易误解的点脚本是文本文件但执行权限是“喂给系统内核”的。内核不会自己读 bash 语法它只看文件头有没有 shebang然后启动对应的解释器。所以一个脚本想通过./方式运行必须同时满足两个条件有执行权限、文件头有可被内核识别的 shebang。缺一不可这正是排障时要往这两个方向分别检查的原因。2. chmod x 实操命令就那几行关键看你怎么用2.1 最常用的三组写法对比给脚本加执行权限最简单直接的就是chmod x。这里“”号是符号模式的加法加上执行位。比如chmod x test.sh执行完以后你再ls -l test.sh第一列的尾巴肯定多出至少一个x。但注意chmod x是对所有“人”都加了执行位当前用户、所属组、其他人都拿到了 x。如果只想给当前用户加写成chmod ux只想给同组人加写成chmod gx只给其他人加那就chmod ox。与之对应的还有绝对值写法chmod 755 test.sh。755 是八进制数字三个数字分别代表 user、group、others 的权限。为什么常用 755因为它等价于rwxr-xr-x也就是文件所有者能读、写、执行组和其他人能读和执行。对脚本来说这是黄金配置——自己能改代码别人能跑但不能乱动。我个人的习惯是本机自己调试用chmod 755放到公开目录分享用chmod 744rwxr--r--让别人只读不执行都行。三者差异归纳起来就是这样命令写法权限结果适合场景chmod x file.shrwxr-xr-x类似 755明确要让所有人都能执行chmod ux file.shrwxr--r--类似 744只让自己执行别人仅可读chmod 755 file.shrwxr-xr-x最常规的脚本权限chmod 700 file.shrwx------含敏感信息的私有脚本2.2 数字模式和符号模式到底怎么换算学chmod时新手最容易懵的是 755、644、777 这种数字模式。其实说白了就是一个中文名为“八进制权限简写”的游戏规则特别简单。r对应数字 4w对应 2x对应 1把这三项加起来得到一个 0 到 7 的数字。比如想设成“可读可写可执行”4217“可读可执行”是 415“只读”是 4。然后一个文件的完整权限按“自己、组、别人”排列755 就是“我自己 7组里 5别人 5”。这套规则我教你一个特别土的记忆法7 相当于“全都要”6 是“能看能改但跑不了”5 是“能看能跑但改不了”4 是“只能看”0 是“啥都干不了”。这样每次写出数字前心里默念一遍就出不了错。符号模式的好处是只改你关心的那部分比如chmod ax就是给所有人补上执行权限chmod u-x则是把自己的执行权限去掉相当灵活。2.3 批量加权限与错误示范一个目录下有几十个脚本总不能一个个chmod。Shell 的通配符这时候就派上用场chmod x *.sh chmod x /opt/scripts/*这会把当前目录下所有以.sh结尾的文件以及/opt/scripts里的每个文件都加上执行权限。但要注意chmod x /opt/scripts/*如果有子目录下一层目录也会被加执行权限。目录的执行权限含义是“能否进入”实际作用不大但也无伤大雅。再进阶一点配合find命令按条件筛选find ./scripts -type f -name *.sh -exec chmod x {} \;exec会把每个符合条件的文件取出来执行一次chmod x这样比通配符更精细化。你还可以用chmod -R x来递归处理但对目录用-R要格外小心一个不小心把一个目录树全变成可执行后患不多但看着难受。我的习惯是不加-R宁可老老实实find因为粒度越细出错概率越低。另有一个常见陷阱你从一个 Windows 风格文档复制命令可能把chmod x script.sh误写成chmod x script.sh这种语法错误报错很快但也说明手敲需要保持专注。3. 光有 chmod x 还不够一脚本跑起来的全部条件3.1 shebang 行是个大前提别忽略很多人在空白文件里写了几行echo保存成run.sh然后chmod x run.sh执行./run.sh报错 “Permission denied”加完 x 以后又报 “cannot execute: required file not found” 或直接没反应。第二种情况的根源十有八九是 shebang 写错或没写。正确写法是文件第一行必须是#!/bin/bash这样的格式#!后面跟着绝对路径指向解释器。假如你写的是 Python 脚本记得这样写#!/usr/bin/env python3 print(hello)用env的好处是它会在你的PATH环境变量里查找python3的位置而不必硬编码/usr/bin/python3。生产环境里虚拟环境、conda 环境多硬编码路径非常容易炸。还有一个必须强调的细节shebang 是#!不能有空格#! /bin/bash这种写法部分系统能容忍但大部分情况下会翻车。3.2 用 ./ 执行、bash 执行、source 执行完全是三码事加了x之后常见的运行方式有三种很多教程把他们混着讲导致新手不知该用哪个。我给个结论./run.sh依赖执行权限和 shebang系统会调用 shebang 里的解释器在当前目录下找到脚本并运行。这是最标准的“脚本执行”姿势。bash run.sh显式用 bash 解释器读取文件并执行不需要 x 权限只要求你有读权限。哪怕ls -l显示完全没 xbash run.sh也能跑。这也是为什么有人抱怨“为什么我 bash 能跑./就不能跑”的原因。source run.sh或source ./run.sh在当前 shell 进程里执行而不是启动一个新进程。对变量、cd、环境变量这类操作source 方式能保留效果./run.sh则在一个子 shell 里执行退出后什么都留不下。source同样不需要 x。三者的差别用个比方./像把车开进洗车房洗完交车bash像你手上直接拿水管冲source像你在车上边开边洗动作直接影响你现在的驾驶状态。日常写脚本用source的场景一般是修改~/.bashrc后立刻生效比如source ~/.bashrc。为了直观我把三种执行方式的差异整理如下执行方式是否需要 x是否启用新进程典型场景./script.sh需要子 shell正常执行脚本bash script.sh不需要子 shell当前系统缺 shebang 时兜底source script.sh不需要当前 shell加载配置、修改环境变量python script.py不需要子进程Python 脚本直接交给解释器3.3 写脚本的入口参数与递归调用前文提过脚本的第一行 shebang 决定了它的运行解释器。如果你不写 shebang直接./run.sh有些系统会默认按/bin/sh处理行为可能跟 bash 不一样。比如 sh 对数组、for循环的部分高阶玩法支持不好导致你在 bash 里调通了的脚本一上/bin/sh就报语法错误。解决方案就是在 shebang 里明确指定#!/bin/bash。另外如果你写的是 Python、Perl、Ruby 等脚本执行权限规则和 shell 脚本一模一样唯一的区别是 shebang 指定的是各自解释器。很多人跑到 Python 课时还在问“为什么我的python3 test.py不用加 x”因为显式指定了解释器权限自然被绕过了。但如果你写成./test.py并配置好 shebang那就必须chmod x test.py才行。这是 Linux 运行脚本的通用逻辑。4. 现场排障加了执行权限为什么还报权限相关错误4.1 Permission denied 的几层真实原因这是整个教程里最有“实战含金量”的部分。建议把排查过程按顺序列成一个清单下次遇到-bash: ./test.sh: Permission denied一条条对照过去。第一层检查确实给了 x 权限吗ls -l看结果如果第一列没有 x那就继续chmod x。第二层检查你在什么文件系统上如果你的脚本放在挂载分区里而这个分区用noexec方式挂载那么无论你怎么chmod x都没用因为整个分区不允许任何文件执行。这种情况在 U 盘、/tmp分区以及公司内部安全加固的服务器上特别常见。可以执行mount | grep 分区路径看到noexec字样就说明问题出在挂载选项。把脚本移到/home或/usr/local/bin下再执行一次基本就解决了。个人建议写自动化脚本时也要规避这个坑别把可执行脚本放在数据盘上长期运行系统盘权限模型干净得多。第三层原因才是 SELinux 或 AppArmor 这类安全模块。CentOS、RHEL、Ubuntu 的部分默认策略会对脚本解释器做额外校验日志里常出现 “Permission denied” 但并不常见。普通用户环境很少撞上这层真要排查可以ausearch -m avc看看审计日志一般出现avc: denied就说明和 SELinux 有关。不过我建议新手先别深入这块等前两层检查完了再说90% 的日常问题都轮不到 SELinux 出场。4.2 报错信息里的“No such file or directory”可能也是权限背锅这是一个特别容易误导人的报错你明明ls能看到脚本文件执行./test.sh却告诉你No such file or directory。其实文件是存在的问题多半出在 shebang 指向的解释器不存在或者文件带着 Windows 换行符。如果你在 Windows 上写脚本然后传到 Linux文件行尾可能是\r\n。shebang 那一行就变成了#!/bin/bash\rLinux 会去找名字里多一个隐藏字符的解释器结果当然找不到。解决办法是用sed或dos2unix清理换行sed -i s/\r$// test.sh4.3 从属关系也是权限游戏的一部分chmod 只管权限位文件的“归属”则由 chown 管。如果你是用普通用户身份执行一个属于另一个用户且权限为 700 的脚本就算你再怎么chmod x也无济于事因为 700 的意思是我只有自己能跑别人一概拒绝。这时候要先看ls -l里的用户名再决定是用 sudo 执行还是让管理员用chown把归属调整成合适对象。补充一个实用判断技巧执行命令时如果提示Operation not permitted而不是Permission denied说明不是权限位问题可能是chattr给文件加了i属性不可变更。这种情况用chattr -i解除属性后再尝试新手遇到概率很小但总得知道存在。4.4 现场排查速查表我把上面的经验压成一张速查表你可以直接贴到笔记里现象可能原因尝试手段Permission denied没有 x 执行位chmod x script.shPermission denied分区以 noexec 挂载移动到 /home 或 /usr/local/binNo such file or directoryshebang 错、解释器不存在检查头行路径which python3No such file or directoryWindows 换行sed -i s/\r$// script.shOperation not permitted文件被 chattr 锁定chattr -i script.shcommand not found脚本路径不在 PATH也未用 ./执行./script.sh或改 PATH4.5 课后自查拿到一个脚本应该怎么跑我现在的个人习惯是从任何渠道拿到一个陌生 shell 脚本文本后先不要无脑chmod x就运行。我会做三件事第一步head -20看内容先确认它在干什么第二步file script.sh看文件类型和换行符格式自动识别是否有问题第三步确认无误后再chmod x最后./script.sh执行。这一套下来能避掉绝大多数低级事故。“先看内容再给权限”这个习惯是从踩坑里学出来的。有一次我明明只是想给脚本加个 x结果在/tmp下执行了一个从网上拉下来的文件它内部一个rm -rf把临时目录清得干干净净。虽然没造成严重损失但那次之后我再也不盲跑脚本了。你也应该养成这种“执行前先读”的习惯这不是保守是基本功。最后分享一个细节习惯也算是我个人收尾时的小偏好写脚本时把set -e放在 shebang 下面可以让脚本在第一个出错命令处自动停下而不是黑着眼一路跑到底再搭配set -u变量没定义直接报错排查脚本权限问题时会非常省心。权限模型的本质是纪律脚本的执行是纪律的执行这两件事做到位你在 Linux 上写脚本的日子会舒服很多。
返回列表