关于 shfmt
shfmt 对 Shell 脚本进行格式化和解析,应用一致的代码风格。支持多种 Shell 方言,可单独或批量格式化脚本文件。
主要功能
- 01格式化单个或多个 Shell 脚本
- 02自动修复 Shell 代码风格
- 03支持 POSIX 和 Bash 等多种 Shell 方言
适用场景
- 01维护团队 Shell 脚本的一致代码风格
- 02在自动化工作流中标准化脚本格式
- 03配合版本控制检查代码一致性
安装
选择你的系统或包管理器,复制命令到终端运行。
安装完成后运行shfmt --version确认安装成功。
命令示例
常用命令按使用顺序排列。
详细介绍
sh
一个 Shell 解析器、格式化工具和解释器。 支持 POSIX Shell、Bash、Zsh 和 mksh。需要 Go 1.26 或更高版本。
快速开始
如需将 Shell 脚本解析为语法树、检查语法树,
并像 shfmt 一样格式化脚本,
请参阅 syntax package。
如需使用遵循 Shell 语义的单次调用辅助函数,
请参阅 shell package:
将命令行拆分为参数并像 shlex 一样重新引用参数、展开字符串中的 $VAR 和 ~,以及使用 ** 进行 glob 匹配或匹配 case 风格的模式。
如需在没有系统 Shell 的情况下运行 Shell 脚本(包括在 Windows 上), 请参阅 interp package; 其处理器可用于配置脚本可以执行的操作和访问的内容。
shfmt
go install mvdan.cc/sh/v3/cmd/shfmt@latest
shfmt 用于格式化 Shell 程序。有关其默认风格的快速概览,请参阅 canonical.sh。例如:
shfmt -l -w script.sh
如需了解更多信息,请参阅其 manpage,可直接以 Markdown 格式查看,也可使用 scdoc 渲染。
可通过 Alpine、Arch、Debian、Docker、Fedora、FreeBSD、 Homebrew、MacPorts、NixOS、OpenSUSE、PyPI、Scoop、Snapcraft、Void 和 webi 获取软件包。
赞助
如果这个项目为你或你的公司节省了时间,不妨考虑 在 GitHub 上赞助我。 月度赞助档位包含多种权益,例如在 README 中展示你的徽标、 优先处理问题,或在你公司的聊天应用中提供直接支持。 一次性赞助档位则可获得关于我的某个项目的交流机会, 或 Go 咨询与指导服务。
贡献
请将错误报告和功能请求提交为详细的问题, 最好附上能够复现错误或说明你期望功能的示例。
除非你是本项目的活跃用户或贡献者,否则临时提交的 AI 补丁并无帮助。请改为提交详细的问题。
注意事项
- 索引 Bash 关联数组时,请始终使用引号。否则,静态解析器 只能假定索引是算术表达式。
$ echo '${array[spaced string]}' | shfmt
<standard input>:1:16: not a valid arithmetic operator: `string`
$ echo '${array[weird!key]}' | shfmt
<standard input>:1:8: reached `!` without matching `[` with `]`
$ echo '${array[dash-string]}' | shfmt
${array[dash - string]}
- 不支持
$((和((的歧义情况。回溯会让解析器更加复杂, 并使通过io.Reader实现流式处理成为不可能。如果$( (表示该用法,POSIX 规范 建议在操作数之间加空格。
$ echo '$((foo); (bar))' | shfmt
1:1: reached ) without matching $(( with ))
-
export、let和declare会被解析为关键字。 这样就能静态构建它们的语法树, 而不是将参数保留为单词切片。 这也是支持declare foo=(bar)的必要条件。 -
整个库完全由 Go 编写,这限制了解释器遵循 POSIX Shell 和 Bash 语义的程度。 例如,Go 不支持派生自身进程,因此子 Shell 会改用 goroutine, 这意味着无法直接使用真实的 PID 和文件描述符。
格式化常见问题
-
格式化工具无法针对某些行禁用格式化;大多数有此需求的用户 是在绕过错误,或是不喜欢某段代码的格式化效果。 因此,请先搜索问题跟踪器,必要时再提交新问题。 对部分文件进行格式化会带来许多边缘情况和复杂性, 而本项目既没有资源,也没有意愿去处理这些问题。
-
我们尽可能避免添加更多格式化选项。每个新增的标志都会与其他标志相互影响, 从而成倍增加开发、维护、测试以及向最终用户准确记录行为所需的人力成本。
-
格式化工具的真正价值在于保持一致性,尤其是对开发团队而言。 我们的目标并非满足每位开发者对理想格式的个人偏好。
JavaScript
解析器和格式化器可通过第三方 npm 包 sh-syntax 使用,该包包含一个编译为 WASM 的本库版本。
此前,我们维护过一个名为 mvdan-sh 的 npm 包,它使用 GopherJS 打包本库的 JS 版本。由于性能不佳且 GopherJS 的开发活跃度有所下降,该 npm 包现已归档。现有用户和新用户都应改用 sh-syntax。
Docker
所有发布标签都会通过 Docker 发布,例如 v3.5.1。
目前,最新的稳定版以 v3 发布,最新的开发版以 latest 发布。
镜像仅包含 shfmt;Alpine Linux 上还提供 -alpine 变体。
要构建 Docker 镜像,请运行:
docker build -t my:tag -f cmd/shfmt/Dockerfile .
要使用 Docker 镜像,请运行:
docker run --rm -u "$(id -u):$(id -g)" -v "$PWD:/mnt" -w /mnt my:tag <shfmt arguments>
相关项目
以下编辑器集成封装了 shfmt:
- BashSupport-Pro - JetBrains IDE 的 Bash 插件
- dockerfmt - 使用 shfmt 的 Dockerfile 格式化工具
- intellij-shellscript - Intellij Jetbrains
shell script插件 - micro - 内置插件的编辑器
- neoformat - (Neo)Vim 插件
- vscode-shfmt - VS Code 插件
- shfmt.el - Emacs 软件包
- Trunk - 通用代码检查工具,可作为 CLI、VS Code 插件和 GitHub Action 使用
其他值得关注的集成包括:
- modd - 一款会响应文件系统变化的开发者工具
- prettier-plugin-sh - 使用 sh-syntax 的 Prettier 插件
- sh-checker - 用于对 shell 脚本进行静态分析的 GitHub Action
- mdformat-shfmt - 用于使用 shfmt 格式化 Markdown 中嵌入的 shell 脚本的 mdformat 插件
- pre-commit-shfmt - pre-commit shfmt 钩子
- tesh - 使用模拟、断言和覆盖率运行脚本