shfmt is a shell formatting tool designed to format, validate, and improve the readability of shell scripts. It supports POSIX Shell, Bash, and mksh syntax, making it versatile for developers working with various shell environments.
Key Features:
Syntax Validation: Ensures scripts adhere to correct syntax while formatting.
Cross-Platform Compatibility: Works seamlessly on Linux, macOS, and Windows.
Integration Support: Can be easily integrated into CI/CD pipelines or editor plugins for automated code styling.
Audience & Benefit:
Ideal for software engineers, DevOps professionals, and anyone writing shell scripts. shfmt helps maintain consistent code style, reduces syntax errors, and enhances readability, ultimately improving development efficiency and code quality. It can be installed via winget for easy setup on Windows systems.
README
sh
A shell parser, formatter, and interpreter. Supports POSIX Shell, Bash, and
mksh. Requires Go 1.24 or later.
Proof of concept shell that uses interp. Note that it's not meant to replace a
POSIX shell at the moment, and its options are intentionally minimalistic.
When indexing Bash associative arrays, always use quotes. The static parser
will otherwise have to assume that the index is an arithmetic expression.
$ echo '${array[spaced string]}' | shfmt
:1:16: not a valid arithmetic operator: string
$ echo '${array[weird!key]}' | shfmt
:1:8: reached ! without matching [ with ]
$ echo '${array[dash-string]}' | shfmt
${array[dash - string]}
$(( and (( ambiguity is not supported. Backtracking would complicate the
parser and make streaming support via io.Reader impossible. The POSIX spec
recommends to space the operands if $( ( is meant.
$ echo '$((foo); (bar))' | shfmt
1:1: reached ) without matching $(( with ))
export, let, and declare are parsed as keywords.
This allows statically building their syntax tree,
as opposed to keeping the arguments as a slice of words.
It is also required to support declare foo=(bar).
Note that this means expansions like declare {a,b}=c are not supported.
The entire library is written in pure Go, which limits how closely the
interpreter can follow POSIX Shell and Bash semantics.
For example, Go does not support forking its own process, so subshells
use a goroutine instead, meaning that real PIDs and file descriptors
cannot be used directly.
JavaScript
The parser and formatter are available as a third party npm package called sh-syntax,
which bundles a version of this library compiled to WASM.
Previously, we maintained an npm package called mvdan-sh which used GopherJS
to bundle a JS version of this library. That npm package is now archived
given its poor performance and GopherJS not being as actively developed.
Any existing or new users should look at sh-syntax instead.
Docker
All release tags are published via Docker, such as v3.5.1.
The latest stable release is currently published as v3,
and the latest development version as latest.
The images only include shfmt; -alpine variants exist on Alpine Linux.