sublime text 保存时自动运行 shell 命令需通过插件实现,推荐使用持续更新的 sublimeonsavebuilder;配置时 "cmd" 必须为数组、"selector" 需匹配语法标识、"shell": true 才支持管道等特性,调试需设 "quiet": false 并检查构建系统启用状态与 path 一致性。

保存时自动运行 Shell 命令的正确触发方式
Sublime Text 本身不支持“保存即执行任意命令”的原生功能,必须通过插件实现;subl 命令行工具或 Save Hook 类插件是唯二可靠路径。直接改 Preferences.sublime-settings 或监听 on_post_save 事件写 Python 插件虽可行,但维护成本高、易被更新覆盖。
- 推荐使用官方插件市场中活跃度高、持续更新的
SublimeOnSaveBuilder(注意不是已停更的OnSave) - 若需调用本地脚本(如
prettier、eslint --fix),确保该命令在 Sublime 的 shell 环境中可执行——Mac/Linux 用户常因 PATH 不一致失败,Windows 用户需确认是否为.bat或.ps1文件且策略允许 - 避免在保存回调里做阻塞式操作(如同步 HTTP 请求),否则会卡住编辑器 UI
SublimeOnSaveBuilder 的最小可用配置
安装插件后,在项目根目录放一个 sublime-build 文件,或在用户设置中配 settings 块。关键不是“怎么写”,而是“哪些字段必须存在”。
-
"cmd"必须是数组格式,哪怕只有一条命令,例如:["npm", "run", "format"],不能写成字符串"npm run format" -
"selector"决定触发范围,常见值:"source.js"(JS 文件)、"text.html.basic"(HTML)、"source.css";多个用逗号分隔,但实际应写成数组:["source.js", "source.ts"] -
"shell"设为true才能解析管道、重定向等 shell 特性(如["sh", "-c", "cat $file | prettier --write"]) - 默认不捕获输出,加
"quiet": false才能在面板看到错误,调试时必开
为什么保存后命令没运行?几个高频断点
最常被忽略的是作用域匹配和构建系统启用状态,而不是语法写错。
- 打开命令面板(
Ctrl+Shift+P/Cmd+Shift+P),输入Set Syntax,确认当前文件语法标识与selector完全一致(比如 Vue 单文件组件默认是text.html.vue,不是source.vue) - 检查右下角状态栏是否显示 “Build System: Automatic” 或你手动选中的构建系统名称;若显示 “None”,则
SublimeOnSaveBuilder不会触发 - 保存时若文件有未保存的编码变更(如从 UTF-8 with BOM 切到 UTF-8),Sublime 可能跳过 hook——先手动保存一次再测试命令
- macOS 上用 Homebrew 安装的
node、prettier常不在/usr/bin/env路径下,建议在cmd中显式写绝对路径,如["/opt/homebrew/bin/prettier", "--write", "$file"]
替代方案:轻量级 Python 插件自定义逻辑
当 SublimeOnSaveBuilder 不满足条件(比如要根据文件扩展名动态选命令,或只在有 package.json 的目录下生效),就得写个极简插件。它比 JSON 配置更灵活,但每次升级 Sublime 后需检查兼容性。
- 菜单 →
Tools→Developer→New Plugin...,替换内容为:
import sublime
import sublime_plugin
import subprocess
import os
class OnSaveRunCommand(sublime_plugin.EventListener):
def on_post_save_async(self, view):
if view.file_name() and view.file_name().endswith(".js"):
folder = os.path.dirname(view.file_name())
subprocess.Popen(["prettier", "--write", view.file_name()], cwd=folder)
on_save_run.py,放在 Packages/User/ 目录下(可通过菜单 Preferences → Browse Packages… 进入)on_post_save_async 而非 on_post_save,避免阻塞主线程;subprocess.Popen 是异步的,不用 wait()
prettier.config.js,得自己加 os.path.exists(os.path.join(folder, "prettier.config.js"))











