如何执行shell脚本:常用操作方法
如何执行shell脚本是Linux运维、自动化任务开发的基础操作,主流执行方式分为赋予可执行权限后直接运行、调用解释器运行、source点命令加载执行三类,适配本地终端、远程SSH会话、定时任务等场景;需要注意,三类方式在变量作用域、工作目录、权限校验上存在明显差异,面向批量生产服务器部署、crontab定时调度场景时,优先选择显式指定解释器的调用方式,降低不同主机默认shell版本不一致带来的兼容问题,普通交互式测试可使用source命令直接在当前终端加载脚本。POSIX标准IEEE1003.1定义了shell命令解释执行的基础规范,bash、dash等解释器均遵循该规范的核心语法要求。
如何执行shell脚本:前置准备
你在执行脚本前,首先确认脚本文件本身的编码与首行shebang声明,shebang格式为!/bin/bash,写在脚本第一行,作用是指定该脚本默认使用的解释器路径;如果这一行缺失,直接执行脚本时系统会沿用当前登录终端的默认shell,不同发行版默认shell可能是bash或者dash,容易出现语法不兼容。你可以使用vimtest.sh创建脚本,写入测试内容后保存退出,再用ls-ltest.sh查看文件权限位,默认新建文件通常没有x可执行权限,这也是很多新手直接输入脚本名提示权限拒绝的核心原因。
权限修改使用chmod命令,常用写法为chmod+xtest.sh,该命令会给文件增加所有者、所属组、其他用户的可执行位;如果你只希望文件所有者拥有执行权限,可使用chmodu+xtest.sh,在多用户服务器环境,按需收紧权限可以降低非授权用户运行脚本的风险。
如何执行shell脚本:三种核心执行方式对比
| 执行方式 | 命令示例 | 变量作用域 | 适用场景 |
|---|---|---|---|
| 赋权后直接运行 | ./test.sh | 子进程独立环境 | 独立自动化任务,不需要修改当前终端变量 |
| 解释器调用运行 | bashtest.sh | 子进程独立环境 | 跨发行版兼容测试,crontab定时任务 |
| source加载执行 | sourcetest.sh或.test.sh | 当前终端会话 | 加载环境变量、别名配置 |
赋权后直接运行,需要在脚本前面加上相对路径./,Linux默认不会把当前目录加入PATH环境变量,只输入test.sh会提示命令找不到,这是高频错误点。该方式会读取脚本第一行shebang,启动一个全新子shell执行脚本,脚本内部修改的环境变量、cd切换目录,在脚本运行结束之后不会保留在原终端。
解释器调用运行不需要给脚本添加x权限,直接手动指定bash、sh等解释器,会忽略脚本内的shebang声明,强制使用你指定的解释器解析脚本。该方式在crontab定时任务里使用较多,因为定时任务环境的PATH变量通常比较精简,显式写全解释器路径,例如/bin/bash/opt/script/test.sh,可以避免定时任务找不到解释器而执行失败。
source(点命令)执行不会新建子进程,所有命令都在你当前终端会话里运行,脚本内export的变量、cd切换目录、修改的别名,执行完成之后会持续生效。该方式的适用边界是交互式终端,不推荐在crontab定时任务中使用source执行业务脚本,定时任务本身没有持久交互式会话,加载的变量无法跨任务保留,还会造成任务状态不可预期。
如何执行shell脚本:远程与后台执行
你需要在远程主机执行shell脚本时,可以通过SSH通道推送执行,命令格式为sshuser@host"bash/path/test.sh",这种方式会在远程主机启动子shell运行脚本,脚本的标准输出、错误输出会回传到本地终端。如果脚本运行耗时较长,需要后台执行,可追加&符号,例如bashtest.sh&,后台进程默认仍然依附当前终端,终端断开连接后进程容易终止,长时间任务可搭配nohup命令,nohupbashtest.sh&,将输出写入nohup.out日志文件,实现终端退出后继续运行。
执行报错排查优先区分三类错误:权限拒绝、解释器找不到、语法错误。权限拒绝对应chmod补权限或者改用解释器调用;解释器找不到,核对shebang里的解释器真实路径,部分精简系统没有/bin/bash,只有dash;语法错误由解释器在解析阶段抛出,可提前使用bash-ntest.sh做语法预检查,不会真正运行脚本,只校验语法是否合法。
脚本执行前建议增加set安全选项。
你可以在脚本头部添加set-e,含义是任意一条命令返回非零退出码,脚本立刻终止,避免错误命令继续向下执行;搭配set-u可以在引用未定义变量时直接报错,适合生产自动化脚本,减少变量漏赋值带来的异常执行。需要留意,set选项只对当前脚本shell生效,不会向外传递到父终端,和source执行的会话级变量规则保持区分。
