Awesome Open Source
Awesome Open Source

sh

Go Reference

A shell parser, formatter, and interpreter. Supports POSIX Shell, Bash, and mksh. Requires Go 1.15 or later.

Quick start

To parse shell scripts, inspect them, and print them out, see the syntax examples.

For high-level operations like performing shell expansions on strings, see the shell examples.

shfmt

GO111MODULE=on go get mvdan.cc/sh/v3/cmd/shfmt

shfmt formats shell programs. See canonical.sh for a quick look at its default style. For example:

shfmt -l -w script.sh

For more information, see its manpage, which can be viewed directly as Markdown or rendered with scdoc.

Packages are available on Alpine, Arch, Docker, FreeBSD, Homebrew, MacPorts, NixOS, Scoop, Snapcraft, Void and webi.

gosh

GO111MODULE=on go get mvdan.cc/sh/v3/cmd/gosh

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.

Fuzzing

This project makes use of go-fuzz to find crashes and hangs in both the parser and the printer. The fuzz-corpus branch contains a corpus to get you started. For example:

git checkout fuzz-corpus
cd syntax
./fuzz

Caveats

  • 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[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 ))
  • Some builtins like export and let 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.

JavaScript

A subset of the Go packages are available as an npm package called mvdan-sh. See the _js directory for more information.

Docker

To build a Docker image, checkout a specific version of the repository and run:

docker build -t my:tag -f cmd/shfmt/Dockerfile .

This creates an image that only includes shfmt. Alternatively, if you want an image that includes alpine, add --target alpine. To use the Docker image, run:

docker run --rm -v $PWD:/mnt -w /mnt my:tag <shfmt arguments>

pre-commit

It is possible to use shfmt with pre-commit and a local repo configuration like:

  - repo: local
    hooks:
      - id: shfmt
        name: shfmt
        minimum_pre_commit_version: 2.4.0
        language: golang
        additional_dependencies: [mvdan.cc/sh/v3/cmd/[email protected]]
        entry: shfmt
        args: [-w]
        types: [shell]

Related projects

The following editor integrations wrap shfmt:

Other noteworthy integrations include:


Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
go (15,152
shell (10,401
bash (628
parser (519
interpreter (215
formatter (133
posix (86
beautify (20